xref: /aoo41x/main/vcl/win/source/gdi/salbmp.cxx (revision fa064a0d)
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                     pSource->mpAssociatedAlpha = 0;
165                 }
166             }
167         }
168 
169         if(!maEntries.empty())
170         {
171             Start();
172         }
173     }
174 };
175 
176 // ------------------------------------------------------------------
177 // Global instance of GdiPlusBuffer which manages Gdiplus::Bitmap
178 // instances
179 
180 static GdiPlusBuffer aGdiPlusBuffer;
181 
182 // ------------------------------------------------------------------
183 // - WinSalBitmap -
184 
185 WinSalBitmap::WinSalBitmap()
186 :   maSize(),
187     mhDIB(0),
188     mhDDB(0),
189     maGdiPlusBitmap(),
190     mpAssociatedAlpha(0),
191     mnBitCount(0)
192 {
193 }
194 
195 // ------------------------------------------------------------------
196 
197 WinSalBitmap::~WinSalBitmap()
198 {
199 	Destroy();
200 }
201 
202 // ------------------------------------------------------------------
203 
204 void WinSalBitmap::Destroy()
205 {
206     if(maGdiPlusBitmap.get())
207     {
208         aGdiPlusBuffer.remEntry(*this);
209     }
210 
211     if( mhDIB )
212 		GlobalFree( mhDIB );
213 	else if( mhDDB )
214 		DeleteObject( mhDDB );
215 
216 	maSize = Size();
217 	mnBitCount = 0;
218 }
219 
220 // ------------------------------------------------------------------
221 
222 GdiPlusBmpPtr WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource) const
223 {
224     WinSalBitmap* pThat = const_cast< WinSalBitmap* >(this);
225 
226     if(maGdiPlusBitmap.get() && pAlphaSource != mpAssociatedAlpha)
227     {
228         // #122350# if associated alpha with which the GDIPlus was constructed has changed
229         // it is necessary to remove it from buffer, reset reference to it and reconstruct
230         pThat->maGdiPlusBitmap.reset();
231         aGdiPlusBuffer.remEntry(const_cast< WinSalBitmap& >(*this));
232     }
233 
234     if(maGdiPlusBitmap.get())
235     {
236         aGdiPlusBuffer.touchEntry(const_cast< WinSalBitmap& >(*this));
237     }
238     else
239     {
240         if(maSize.Width() > 0 && maSize.Height() > 0)
241         {
242             if(pAlphaSource)
243             {
244                 pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap(*pAlphaSource));
245                 pThat->mpAssociatedAlpha = pAlphaSource;
246             }
247             else
248             {
249                 pThat->maGdiPlusBitmap.reset(pThat->ImplCreateGdiPlusBitmap());
250                 pThat->mpAssociatedAlpha = 0;
251             }
252 
253             if(maGdiPlusBitmap.get())
254             {
255                 aGdiPlusBuffer.addEntry(*pThat);
256             }
257         }
258     }
259 
260     return maGdiPlusBitmap;
261 }
262 
263 // ------------------------------------------------------------------
264 
265 Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap()
266 {
267     Gdiplus::Bitmap* pRetval(0);
268     WinSalBitmap* pSalRGB = const_cast< WinSalBitmap* >(this);
269     WinSalBitmap* pExtraWinSalRGB = 0;
270 
271     if(!pSalRGB->ImplGethDIB())
272     {
273         // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
274         pExtraWinSalRGB = new WinSalBitmap();
275         pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount());
276         pSalRGB = pExtraWinSalRGB;
277     }
278 
279     BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(true);
280     BitmapBuffer* pExtraRGB = 0;
281 
282     if(pRGB && BMP_FORMAT_24BIT_TC_BGR != (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN))
283     {
284         // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
285         SalTwoRect aSalTwoRect;
286 
287         aSalTwoRect.mnSrcX = aSalTwoRect.mnSrcY = aSalTwoRect.mnDestX = aSalTwoRect.mnDestY = 0;
288         aSalTwoRect.mnSrcWidth = aSalTwoRect.mnDestWidth = pRGB->mnWidth;
289         aSalTwoRect.mnSrcHeight = aSalTwoRect.mnDestHeight = pRGB->mnHeight;
290 
291         pExtraRGB = StretchAndConvert(
292             *pRGB,
293             aSalTwoRect,
294             BMP_FORMAT_24BIT_TC_BGR,
295             0);
296 
297         pSalRGB->ReleaseBuffer(pRGB, true);
298         pRGB = pExtraRGB;
299     }
300 
301     if(pRGB
302         && pRGB->mnWidth > 0
303         && pRGB->mnHeight > 0
304         && BMP_FORMAT_24BIT_TC_BGR == (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN))
305     {
306         const sal_uInt32 nW(pRGB->mnWidth);
307         const sal_uInt32 nH(pRGB->mnHeight);
308 
309         pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat24bppRGB);
310 
311         if(pRetval)
312         {
313             sal_uInt8* pSrcRGB(pRGB->mpBits);
314             const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
315             const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN);
316 
317             for(sal_uInt32 y(0); y < nH; y++)
318             {
319                 const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
320 
321                 for(sal_uInt32 x(0); x < nW; x++)
322                 {
323                     const sal_uInt8 nB(*pSrcRGB++);
324                     const sal_uInt8 nG(*pSrcRGB++);
325                     const sal_uInt8 nR(*pSrcRGB++);
326 
327                     pRetval->SetPixel(x, nYInsert, Gdiplus::Color(nR, nG, nB));
328                 }
329 
330                 pSrcRGB += nExtraRGB;
331             }
332         }
333     }
334 
335     if(pExtraRGB)
336     {
337         delete pExtraRGB;
338     }
339     else
340     {
341         pSalRGB->ReleaseBuffer(pRGB, true);
342     }
343 
344     if(pExtraWinSalRGB)
345     {
346         delete pExtraWinSalRGB;
347     }
348 
349     return pRetval;
350 }
351 
352 // ------------------------------------------------------------------
353 
354 Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap& rAlphaSource)
355 {
356     Gdiplus::Bitmap* pRetval(0);
357     WinSalBitmap* pSalRGB = const_cast< WinSalBitmap* >(this);
358     WinSalBitmap* pExtraWinSalRGB = 0;
359 
360     if(!pSalRGB->ImplGethDIB())
361     {
362         // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
363         pExtraWinSalRGB = new WinSalBitmap();
364         pExtraWinSalRGB->Create(*pSalRGB, pSalRGB->GetBitCount());
365         pSalRGB = pExtraWinSalRGB;
366     }
367 
368     BitmapBuffer* pRGB = pSalRGB->AcquireBuffer(true);
369     BitmapBuffer* pExtraRGB = 0;
370 
371     if(pRGB && BMP_FORMAT_24BIT_TC_BGR != (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN))
372     {
373         // convert source bitmap to BMP_FORMAT_24BIT_TC_BGR format if not yet in that format
374         SalTwoRect aSalTwoRect;
375 
376         aSalTwoRect.mnSrcX = aSalTwoRect.mnSrcY = aSalTwoRect.mnDestX = aSalTwoRect.mnDestY = 0;
377         aSalTwoRect.mnSrcWidth = aSalTwoRect.mnDestWidth = pRGB->mnWidth;
378         aSalTwoRect.mnSrcHeight = aSalTwoRect.mnDestHeight = pRGB->mnHeight;
379 
380         pExtraRGB = StretchAndConvert(
381             *pRGB,
382             aSalTwoRect,
383             BMP_FORMAT_24BIT_TC_BGR,
384             0);
385 
386         pSalRGB->ReleaseBuffer(pRGB, true);
387         pRGB = pExtraRGB;
388     }
389 
390     WinSalBitmap* pSalA = const_cast< WinSalBitmap* >(&rAlphaSource);
391     WinSalBitmap* pExtraWinSalA = 0;
392 
393     if(!pSalA->ImplGethDIB())
394     {
395         // we need DIB for success with AcquireBuffer, create a replacement WinSalBitmap
396         pExtraWinSalA = new WinSalBitmap();
397         pExtraWinSalA->Create(*pSalA, pSalA->GetBitCount());
398         pSalA = pExtraWinSalA;
399     }
400 
401     BitmapBuffer* pA = pSalA->AcquireBuffer(true);
402     BitmapBuffer* pExtraA = 0;
403 
404     if(pA && BMP_FORMAT_8BIT_PAL != (pA->mnFormat & ~BMP_FORMAT_TOP_DOWN))
405     {
406         // convert alpha bitmap to BMP_FORMAT_8BIT_PAL format if not yet in that format
407         SalTwoRect aSalTwoRect;
408 
409         aSalTwoRect.mnSrcX = aSalTwoRect.mnSrcY = aSalTwoRect.mnDestX = aSalTwoRect.mnDestY = 0;
410         aSalTwoRect.mnSrcWidth = aSalTwoRect.mnDestWidth = pA->mnWidth;
411         aSalTwoRect.mnSrcHeight = aSalTwoRect.mnDestHeight = pA->mnHeight;
412         const BitmapPalette& rTargetPalette = Bitmap::GetGreyPalette(256);
413 
414         pExtraA = StretchAndConvert(
415             *pA,
416             aSalTwoRect,
417             BMP_FORMAT_8BIT_PAL,
418             &rTargetPalette);
419 
420         pSalA->ReleaseBuffer(pA, true);
421         pA = pExtraA;
422     }
423 
424     if(pRGB
425         && pA
426         && pRGB->mnWidth > 0
427         && pRGB->mnHeight > 0
428         && pRGB->mnWidth == pA->mnWidth
429         && pRGB->mnHeight == pA->mnHeight
430         && BMP_FORMAT_24BIT_TC_BGR == (pRGB->mnFormat & ~BMP_FORMAT_TOP_DOWN)
431         && BMP_FORMAT_8BIT_PAL == (pA->mnFormat & ~BMP_FORMAT_TOP_DOWN))
432     {
433         // we have alpha and bitmap in known formats, create GdiPlus Bitmap as 32bit ARGB
434         const sal_uInt32 nW(pRGB->mnWidth);
435         const sal_uInt32 nH(pRGB->mnHeight);
436 
437         pRetval = new Gdiplus::Bitmap(nW, nH, PixelFormat32bppARGB);
438 
439         if(pRetval)
440         {
441             sal_uInt8* pSrcRGB(pRGB->mpBits);
442             sal_uInt8* pSrcA(pA->mpBits);
443             const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
444             const sal_uInt32 nExtraA(pA->mnScanlineSize - nW);
445             const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN);
446 
447             for(sal_uInt32 y(0); y < nH; y++)
448             {
449                 const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
450 
451                 for(sal_uInt32 x(0); x < nW; x++)
452                 {
453                     const sal_uInt8 nB(*pSrcRGB++);
454                     const sal_uInt8 nG(*pSrcRGB++);
455                     const sal_uInt8 nR(*pSrcRGB++);
456                     const sal_uInt8 nA(0xff - *pSrcA++);
457 
458                     pRetval->SetPixel(x, nYInsert, Gdiplus::Color(nA, nR, nG, nB));
459                 }
460 
461                 pSrcRGB += nExtraRGB;
462                 pSrcA += nExtraA;
463             }
464         }
465     }
466 
467     if(pExtraA)
468     {
469         delete pExtraA;
470     }
471     else
472     {
473         pSalA->ReleaseBuffer(pA, true);
474     }
475 
476     if(pExtraWinSalA)
477     {
478         delete pExtraWinSalA;
479     }
480 
481     if(pExtraRGB)
482     {
483         delete pExtraRGB;
484     }
485     else
486     {
487         pSalRGB->ReleaseBuffer(pRGB, true);
488     }
489 
490     if(pExtraWinSalRGB)
491     {
492         delete pExtraWinSalRGB;
493     }
494 
495     return pRetval;
496 }
497 
498 // ------------------------------------------------------------------
499 
500 bool WinSalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle )
501 {
502 	bool bRet = TRUE;
503 
504 	if( bDIB )
505 		mhDIB = (HGLOBAL) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, TRUE ) : hBitmap );
506 	else
507 		mhDDB = (HBITMAP) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, FALSE ) : hBitmap );
508 
509 	if( mhDIB )
510 	{
511 		PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) GlobalLock( mhDIB );
512 
513 		maSize = Size( pBIH->biWidth, pBIH->biHeight );
514 		mnBitCount = pBIH->biBitCount;
515 
516 		if( mnBitCount )
517 			mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
518 
519 		GlobalUnlock( mhDIB );
520 	}
521 	else if( mhDDB )
522 	{
523 		BITMAP	aDDBInfo;
524 
525 		if( WIN_GetObject( mhDDB, sizeof( BITMAP ), &aDDBInfo ) )
526 		{
527 			maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
528 			mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
529 
530 			if( mnBitCount )
531 			{
532 				mnBitCount = ( mnBitCount <= 1 ) ? 1 :
533 							 ( mnBitCount <= 4 ) ? 4 :
534 							 ( mnBitCount <= 8 ) ? 8 : 24;
535 			}
536 		}
537 		else
538 		{
539 			mhDDB = 0;
540 			bRet = FALSE;
541 		}
542 	}
543 	else
544 		bRet = FALSE;
545 
546 	return bRet;
547 }
548 
549 // ------------------------------------------------------------------
550 
551 bool WinSalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
552 {
553 	bool bRet = FALSE;
554 
555 	mhDIB = ImplCreateDIB( rSize, nBitCount, rPal );
556 
557 	if( mhDIB )
558 	{
559 		maSize = rSize;
560 		mnBitCount = nBitCount;
561 		bRet = TRUE;
562 	}
563 
564 	return bRet;
565 }
566 
567 // ------------------------------------------------------------------
568 
569 bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap )
570 {
571 	bool bRet = FALSE;
572     const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
573 
574 	if ( rSalBitmap.mhDIB || rSalBitmap.mhDDB )
575 	{
576 		HANDLE hNewHdl = ImplCopyDIBOrDDB( rSalBitmap.mhDIB ? rSalBitmap.mhDIB : rSalBitmap.mhDDB,
577 										   rSalBitmap.mhDIB != 0 );
578 
579 		if ( hNewHdl )
580 		{
581 			if( rSalBitmap.mhDIB )
582 				mhDIB = (HGLOBAL) hNewHdl;
583 			else if( rSalBitmap.mhDDB )
584 				mhDDB = (HBITMAP) hNewHdl;
585 
586 			maSize = rSalBitmap.maSize;
587 			mnBitCount = rSalBitmap.mnBitCount;
588 
589 			bRet = TRUE;
590 		}
591 	}
592 
593 	return bRet;
594 }
595 
596 // ------------------------------------------------------------------
597 
598 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
599 {
600 	bool bRet = FALSE;
601 
602     const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
603     WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
604 
605 	if( rSalBmp.mhDIB )
606 	{
607 		PBITMAPINFO 		pBI = (PBITMAPINFO) GlobalLock( rSalBmp.mhDIB );
608 		PBITMAPINFOHEADER	pBIH = (PBITMAPINFOHEADER) pBI;
609 		HDC 				hDC  = pGraphics->getHDC();
610 		HBITMAP 			hNewDDB;
611 		BITMAP				aDDBInfo;
612 		PBYTE				pBits = (PBYTE) pBI + *(DWORD*) pBI +
613 							ImplGetDIBColorCount( rSalBmp.mhDIB ) * sizeof( RGBQUAD );
614 
615 		if( pBIH->biBitCount == 1 )
616 		{
617 			hNewDDB = CreateBitmap( pBIH->biWidth, pBIH->biHeight, 1, 1, NULL );
618 
619 			if( hNewDDB )
620 				SetDIBits( hDC, hNewDDB, 0, pBIH->biHeight, pBits, pBI, DIB_RGB_COLORS );
621 		}
622 		else
623 			hNewDDB = CreateDIBitmap( hDC, (PBITMAPINFOHEADER) pBI, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
624 
625 		GlobalUnlock( rSalBmp.mhDIB );
626 
627 		if( hNewDDB && WIN_GetObject( hNewDDB, sizeof( BITMAP ), &aDDBInfo ) )
628 		{
629 			mhDDB = hNewDDB;
630 			maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
631 			mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
632 
633 			bRet = TRUE;
634 		}
635 		else if( hNewDDB )
636 			DeleteObject( hNewDDB );
637 	}
638 
639 	return bRet;
640 }
641 
642 // ------------------------------------------------------------------
643 
644 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, sal_uInt16 nNewBitCount )
645 {
646 	bool bRet = FALSE;
647 
648     const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
649 
650 	if( rSalBmp.mhDDB )
651 	{
652 		mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() );
653 
654 		if( mhDIB )
655 		{
656 			PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
657 			const int	nLines = (int) rSalBmp.maSize.Height();
658 			HDC 		hDC = GetDC( 0 );
659 			PBYTE		pBits = (PBYTE) pBI + *(DWORD*) pBI +
660 								ImplGetDIBColorCount( mhDIB ) * sizeof( RGBQUAD );
661 			SalData*	pSalData = GetSalData();
662 			HPALETTE	hOldPal = 0;
663 
664 			if ( pSalData->mhDitherPal )
665 			{
666 				hOldPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
667 				RealizePalette( hDC );
668 			}
669 
670 			if( GetDIBits( hDC, rSalBmp.mhDDB, 0, nLines, pBits, pBI, DIB_RGB_COLORS ) == nLines )
671 			{
672 				GlobalUnlock( mhDIB );
673 				maSize = rSalBmp.maSize;
674 				mnBitCount = nNewBitCount;
675 				bRet = TRUE;
676 			}
677 			else
678 			{
679 				GlobalUnlock( mhDIB );
680 				GlobalFree( mhDIB );
681 				mhDIB = 0;
682 			}
683 
684 			if( hOldPal )
685 				SelectPalette( hDC, hOldPal, TRUE );
686 
687 			ReleaseDC( 0, hDC );
688 		}
689 	}
690 
691 	return bRet;
692 }
693 
694 // ------------------------------------------------------------------
695 
696 sal_uInt16 WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB )
697 {
698 	sal_uInt16 nColors = 0;
699 
700 	if( hDIB )
701 	{
702 		PBITMAPINFO 		pBI = (PBITMAPINFO) GlobalLock( hDIB );
703 		PBITMAPINFOHEADER	pBIH = (PBITMAPINFOHEADER) pBI;
704 
705 		if ( pBIH->biSize != sizeof( BITMAPCOREHEADER ) )
706 		{
707 			if( pBIH->biBitCount <= 8 )
708 			{
709 				if ( pBIH->biClrUsed )
710 					nColors = (sal_uInt16) pBIH->biClrUsed;
711 				else
712 					nColors = 1 << pBIH->biBitCount;
713 			}
714 		}
715 		else if( ( (PBITMAPCOREHEADER) pBI )->bcBitCount <= 8 )
716 			nColors = 1 << ( (PBITMAPCOREHEADER) pBI )->bcBitCount;
717 
718 		GlobalUnlock( hDIB );
719 	}
720 
721 	return nColors;
722 }
723 
724 // ------------------------------------------------------------------
725 
726 HGLOBAL WinSalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rPal )
727 {
728 	DBG_ASSERT( nBits == 1 || nBits == 4 || nBits == 8 || nBits == 16 || nBits == 24, "Unsupported BitCount!" );
729 
730 	HGLOBAL hDIB = 0;
731 
732 	if( rSize.Width() <= 0 || rSize.Height() <= 0 )
733 		return hDIB;
734 
735 	// calculate bitmap size in Bytes
736 	const sal_uLong nAlignedWidth4Bytes = AlignedWidth4Bytes( nBits * rSize.Width() );
737 	const sal_uLong nImageSize = nAlignedWidth4Bytes * rSize.Height();
738 	bool bOverflow = (nImageSize / nAlignedWidth4Bytes) != rSize.Height();
739 	if( bOverflow )
740 		return hDIB;
741 
742 	// allocate bitmap memory including header and palette
743 	const sal_uInt16 nColors = (nBits <= 8) ? (1 << nBits) : 0;
744 	const sal_uLong nHeaderSize = sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD );
745 	bOverflow = (nHeaderSize + nImageSize) < nImageSize;
746 	if( bOverflow )
747 		return hDIB;
748 
749 	hDIB = GlobalAlloc( GHND, nHeaderSize + nImageSize );
750 	if( !hDIB )
751 		return hDIB;
752 
753 	PBITMAPINFO pBI = static_cast<PBITMAPINFO>( GlobalLock( hDIB ) );
754 	PBITMAPINFOHEADER pBIH = reinterpret_cast<PBITMAPINFOHEADER>( pBI );
755 
756 	pBIH->biSize = sizeof( BITMAPINFOHEADER );
757 	pBIH->biWidth = rSize.Width();
758 	pBIH->biHeight = rSize.Height();
759 	pBIH->biPlanes = 1;
760 	pBIH->biBitCount = nBits;
761 	pBIH->biCompression = BI_RGB;
762 	pBIH->biSizeImage = nImageSize;
763 	pBIH->biXPelsPerMeter = 0;
764 	pBIH->biYPelsPerMeter = 0;
765 	pBIH->biClrUsed = 0;
766 	pBIH->biClrImportant = 0;
767 
768 	if( nColors )
769 	{
770 		// copy the palette entries if any
771 		const sal_uInt16 nMinCount = Min( nColors, rPal.GetEntryCount() );
772 		if( nMinCount )
773 			memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof(RGBQUAD) );
774 	}
775 
776 	GlobalUnlock( hDIB );
777 
778 	return hDIB;
779 }
780 
781 // ------------------------------------------------------------------
782 
783 HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
784 {
785 	HANDLE	hCopy = 0;
786 
787 	if ( bDIB && hHdl )
788 	{
789 		const sal_uLong nSize = GlobalSize( hHdl );
790 
791 		if ( (hCopy = GlobalAlloc( GHND, nSize  )) != 0 )
792 		{
793 			memcpy( (LPSTR) GlobalLock( hCopy ), (LPSTR) GlobalLock( hHdl ), nSize );
794 
795 			GlobalUnlock( hCopy );
796 			GlobalUnlock( hHdl );
797 		}
798 	}
799 	else if ( hHdl )
800 	{
801 		BITMAP aBmp;
802 
803 		// Source-Bitmap nach Groesse befragen
804 		WIN_GetObject( hHdl, sizeof( BITMAP ), (LPSTR) &aBmp );
805 
806 		// Destination-Bitmap erzeugen
807 		if ( (hCopy = CreateBitmapIndirect( &aBmp )) != 0 )
808 		{
809 			HDC 	hBmpDC = CreateCompatibleDC( 0 );
810 			HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hHdl );
811 			HDC 	hCopyDC = CreateCompatibleDC( hBmpDC );
812 			HBITMAP hCopyOld = (HBITMAP) SelectObject( hCopyDC, hCopy );
813 
814 			BitBlt( hCopyDC, 0, 0, aBmp.bmWidth, aBmp.bmHeight, hBmpDC, 0, 0, SRCCOPY );
815 
816 			SelectObject( hCopyDC, hCopyOld );
817 			DeleteDC( hCopyDC );
818 
819 			SelectObject( hBmpDC, hBmpOld );
820 			DeleteDC( hBmpDC );
821 		}
822 	}
823 
824 	return hCopy;
825 }
826 
827 // ------------------------------------------------------------------
828 
829 BitmapBuffer* WinSalBitmap::AcquireBuffer( bool /*bReadOnly*/ )
830 {
831 	BitmapBuffer* pBuffer = NULL;
832 
833 	if( mhDIB )
834 	{
835 		PBITMAPINFO 		pBI = (PBITMAPINFO) GlobalLock( mhDIB );
836 		PBITMAPINFOHEADER	pBIH = (PBITMAPINFOHEADER) pBI;
837 
838 		if( ( pBIH->biCompression == BI_RLE4 ) || ( pBIH->biCompression == BI_RLE8 ) )
839 		{
840 			Size	aSizePix( pBIH->biWidth, pBIH->biHeight );
841 			HGLOBAL hNewDIB = ImplCreateDIB( aSizePix, pBIH->biBitCount, BitmapPalette() );
842 
843 			if( hNewDIB )
844 			{
845 				PBITMAPINFO 		pNewBI = (PBITMAPINFO) GlobalLock( hNewDIB );
846 				PBITMAPINFOHEADER	pNewBIH = (PBITMAPINFOHEADER) pNewBI;
847 				const sal_uInt16		nColorCount = ImplGetDIBColorCount( hNewDIB );
848 				const sal_uLong 		nOffset = *(DWORD*) pBI + nColorCount * sizeof( RGBQUAD );
849 				BYTE*				pOldBits = (PBYTE) pBI + nOffset;
850 				BYTE*				pNewBits = (PBYTE) pNewBI + nOffset;
851 
852 				memcpy( pNewBI, pBI, nOffset );
853 				pNewBIH->biCompression = 0;
854 				ImplDecodeRLEBuffer( pOldBits, pNewBits, aSizePix, pBIH->biCompression == BI_RLE4 );
855 
856 				GlobalUnlock( mhDIB );
857 				GlobalFree( mhDIB );
858 				mhDIB = hNewDIB;
859 				pBI = pNewBI;
860 				pBIH = pNewBIH;
861 			}
862 		}
863 
864 		if( pBIH->biPlanes == 1 )
865 		{
866 			pBuffer = new BitmapBuffer;
867 
868 			pBuffer->mnFormat = BMP_FORMAT_BOTTOM_UP |
869 								( pBIH->biBitCount == 1 ? BMP_FORMAT_1BIT_MSB_PAL :
870 								  pBIH->biBitCount == 4 ? BMP_FORMAT_4BIT_MSN_PAL :
871 								  pBIH->biBitCount == 8 ? BMP_FORMAT_8BIT_PAL :
872 								  pBIH->biBitCount == 16 ? BMP_FORMAT_16BIT_TC_LSB_MASK :
873 								  pBIH->biBitCount == 24 ? BMP_FORMAT_24BIT_TC_BGR :
874 								  pBIH->biBitCount == 32 ? BMP_FORMAT_32BIT_TC_MASK : 0UL );
875 
876 			if( BMP_SCANLINE_FORMAT( pBuffer->mnFormat ) )
877 			{
878 				pBuffer->mnWidth = maSize.Width();
879 				pBuffer->mnHeight = maSize.Height();
880 				pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->biBitCount );
881 				pBuffer->mnBitCount = (sal_uInt16) pBIH->biBitCount;
882 
883 				if( pBuffer->mnBitCount <= 8 )
884 				{
885 					const sal_uInt16 nPalCount = ImplGetDIBColorCount( mhDIB );
886 
887 					pBuffer->maPalette.SetEntryCount( nPalCount );
888 					memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->bmiColors, nPalCount * sizeof( RGBQUAD ) );
889 					pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nPalCount * sizeof( RGBQUAD );
890 				}
891 				else if( ( pBIH->biBitCount == 16 ) || ( pBIH->biBitCount == 32 ) )
892 				{
893 					sal_uLong nOffset = 0UL;
894 
895 					if( pBIH->biCompression == BI_BITFIELDS )
896 					{
897 						nOffset = 3 * sizeof( RGBQUAD );
898 						pBuffer->maColorMask = ColorMask( *(UINT32*) &pBI->bmiColors[ 0 ],
899 														  *(UINT32*) &pBI->bmiColors[ 1 ],
900 														  *(UINT32*) &pBI->bmiColors[ 2 ] );
901 					}
902 					else if( pBIH->biBitCount == 16 )
903 						pBuffer->maColorMask = ColorMask( 0x00007c00UL, 0x000003e0UL, 0x0000001fUL );
904 					else
905 						pBuffer->maColorMask = ColorMask( 0x00ff0000UL, 0x0000ff00UL, 0x000000ffUL );
906 
907 					pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nOffset;
908 				}
909 				else
910 					pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI;
911 			}
912 			else
913 			{
914 				GlobalUnlock( mhDIB );
915 				delete pBuffer;
916 				pBuffer = NULL;
917 			}
918 		}
919 		else
920 			GlobalUnlock( mhDIB );
921 	}
922 
923 	return pBuffer;
924 }
925 
926 // ------------------------------------------------------------------
927 
928 void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
929 {
930 	if( pBuffer )
931 	{
932 		if( mhDIB )
933 		{
934 			if( !bReadOnly && !!pBuffer->maPalette )
935 			{
936 				PBITMAPINFO 	pBI = (PBITMAPINFO) GlobalLock( mhDIB );
937 				const sal_uInt16	nCount = pBuffer->maPalette.GetEntryCount();
938 				const sal_uInt16	nDIBColorCount = ImplGetDIBColorCount( mhDIB );
939 				memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), Min( nDIBColorCount, nCount ) * sizeof( RGBQUAD ) );
940 				GlobalUnlock( mhDIB );
941 			}
942 
943 			GlobalUnlock( mhDIB );
944 		}
945 
946 		delete pBuffer;
947 	}
948 }
949 
950 // ------------------------------------------------------------------
951 
952 void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
953 									 const Size& rSizePixel, bool bRLE4 )
954 {
955 	HPBYTE			pRLE = (HPBYTE) pSrcBuf;
956 	HPBYTE			pDIB = (HPBYTE) pDstBuf;
957 	HPBYTE			pRow = (HPBYTE) pDstBuf;
958 	sal_uLong			nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) );
959 	HPBYTE			pLast = pDIB + rSizePixel.Height() * nWidthAl - 1;
960 	sal_uLong			nCountByte;
961 	sal_uLong			nRunByte;
962 	sal_uLong			nX = 0;
963 	sal_uLong			i;
964 	BYTE			cTmp;
965 	bool			bEndDecoding = FALSE;
966 
967 	if( pRLE && pDIB )
968 	{
969 		do
970 		{
971 			if( ( nCountByte = *pRLE++ ) == 0 )
972 			{
973 				nRunByte = *pRLE++;
974 
975 				if( nRunByte > 2UL )
976 				{
977 					if( bRLE4 )
978 					{
979 						nCountByte = nRunByte >> 1UL;
980 
981 						for( i = 0; i < nCountByte; i++ )
982 						{
983 							cTmp = *pRLE++;
984 							ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
985 							ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
986 						}
987 
988 						if( nRunByte & 1 )
989 							ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
990 
991 						if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
992 							pRLE++;
993 					}
994 					else
995 					{
996 						memcpy( &pDIB[ nX ], pRLE, nRunByte );
997 						pRLE += nRunByte;
998 						nX += nRunByte;
999 
1000 						if( nRunByte & 1 )
1001 							pRLE++;
1002 					}
1003 				}
1004 				else if( !nRunByte )
1005 				{
1006 					pDIB = ( pRow += nWidthAl );
1007 					nX = 0UL;
1008 				}
1009 				else if( nRunByte == 1 )
1010 					bEndDecoding = TRUE;
1011 				else
1012 				{
1013 					nX += *pRLE++;
1014 					pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
1015 				}
1016 			}
1017 			else
1018 			{
1019 				cTmp = *pRLE++;
1020 
1021 				if( bRLE4 )
1022 				{
1023 					nRunByte = nCountByte >> 1;
1024 
1025 					for( i = 0; i < nRunByte; i++ )
1026 					{
1027 						ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
1028 						ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
1029 					}
1030 
1031 					if( nCountByte & 1 )
1032 						ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
1033 				}
1034 				else
1035 				{
1036 					for( i = 0; i < nCountByte; i++ )
1037 						pDIB[ nX++ ] = cTmp;
1038 				}
1039 			}
1040 		}
1041 		while( !bEndDecoding && ( pDIB <= pLast ) );
1042 	}
1043 }
1044 
1045 bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
1046 {
1047     bool bRet = false;
1048     if( mhDIB || mhDDB )
1049     {
1050         bRet = true;
1051         rData.pDIB = mhDIB;
1052         rData.pDDB = mhDDB;
1053         const Size& rSize = GetSize ();
1054         rData.mnWidth = rSize.Width();
1055         rData.mnHeight = rSize.Height();
1056     }
1057     return bRet;
1058 }
1059