xref: /aoo41x/main/vcl/win/source/gdi/salbmp.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <tools/svwin.h>
32 
33 #include <vcl/bitmap.hxx> // for BitmapSystemData
34 #include <vcl/salbtype.hxx>
35 
36 #include <win/wincomp.hxx>
37 #include <win/salgdi.h>
38 #include <win/saldata.hxx>
39 #include <win/salbmp.h>
40 
41 #include <string.h>
42 
43 // -----------
44 // - Inlines -
45 // -----------
46 
47 inline void ImplSetPixel4( const HPBYTE pScanline, long nX, const BYTE cIndex )
48 {
49 	BYTE& rByte = pScanline[ nX >> 1 ];
50 
51 	( nX & 1 ) ? ( rByte &= 0xf0, rByte |= ( cIndex & 0x0f ) ) :
52 				 ( rByte &= 0x0f, rByte |= ( cIndex << 4 ) );
53 }
54 
55 // ----------------
56 // - WinSalBitmap -
57 // ----------------
58 
59 WinSalBitmap::WinSalBitmap() :
60 		mhDIB		( 0 ),
61 		mhDDB		( 0 ),
62 		mnBitCount	( 0 )
63 {
64 }
65 
66 // ------------------------------------------------------------------
67 
68 WinSalBitmap::~WinSalBitmap()
69 {
70 	Destroy();
71 }
72 
73 // ------------------------------------------------------------------
74 
75 bool WinSalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle )
76 {
77 	bool bRet = TRUE;
78 
79 	if( bDIB )
80 		mhDIB = (HGLOBAL) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, TRUE ) : hBitmap );
81 	else
82 		mhDDB = (HBITMAP) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, FALSE ) : hBitmap );
83 
84 	if( mhDIB )
85 	{
86 		PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) GlobalLock( mhDIB );
87 
88 		maSize = Size( pBIH->biWidth, pBIH->biHeight );
89 		mnBitCount = pBIH->biBitCount;
90 
91 		if( mnBitCount )
92 			mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
93 
94 		GlobalUnlock( mhDIB );
95 	}
96 	else if( mhDDB )
97 	{
98 		BITMAP	aDDBInfo;
99 
100 		if( WIN_GetObject( mhDDB, sizeof( BITMAP ), &aDDBInfo ) )
101 		{
102 			maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
103 			mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
104 
105 			if( mnBitCount )
106 			{
107 				mnBitCount = ( mnBitCount <= 1 ) ? 1 :
108 							 ( mnBitCount <= 4 ) ? 4 :
109 							 ( mnBitCount <= 8 ) ? 8 : 24;
110 			}
111 		}
112 		else
113 		{
114 			mhDDB = 0;
115 			bRet = FALSE;
116 		}
117 	}
118 	else
119 		bRet = FALSE;
120 
121 	return bRet;
122 }
123 
124 // ------------------------------------------------------------------
125 
126 bool WinSalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
127 {
128 	bool bRet = FALSE;
129 
130 	mhDIB = ImplCreateDIB( rSize, nBitCount, rPal );
131 
132 	if( mhDIB )
133 	{
134 		maSize = rSize;
135 		mnBitCount = nBitCount;
136 		bRet = TRUE;
137 	}
138 
139 	return bRet;
140 }
141 
142 // ------------------------------------------------------------------
143 
144 bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap )
145 {
146 	bool bRet = FALSE;
147     const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
148 
149 	if ( rSalBitmap.mhDIB || rSalBitmap.mhDDB )
150 	{
151 		HANDLE hNewHdl = ImplCopyDIBOrDDB( rSalBitmap.mhDIB ? rSalBitmap.mhDIB : rSalBitmap.mhDDB,
152 										   rSalBitmap.mhDIB != 0 );
153 
154 		if ( hNewHdl )
155 		{
156 			if( rSalBitmap.mhDIB )
157 				mhDIB = (HGLOBAL) hNewHdl;
158 			else if( rSalBitmap.mhDDB )
159 				mhDDB = (HBITMAP) hNewHdl;
160 
161 			maSize = rSalBitmap.maSize;
162 			mnBitCount = rSalBitmap.mnBitCount;
163 
164 			bRet = TRUE;
165 		}
166 	}
167 
168 	return bRet;
169 }
170 
171 // ------------------------------------------------------------------
172 
173 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
174 {
175 	bool bRet = FALSE;
176 
177     const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
178     WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
179 
180 	if( rSalBmp.mhDIB )
181 	{
182 		PBITMAPINFO 		pBI = (PBITMAPINFO) GlobalLock( rSalBmp.mhDIB );
183 		PBITMAPINFOHEADER	pBIH = (PBITMAPINFOHEADER) pBI;
184 		HDC 				hDC  = pGraphics->mhDC;
185 		HBITMAP 			hNewDDB;
186 		BITMAP				aDDBInfo;
187 		PBYTE				pBits = (PBYTE) pBI + *(DWORD*) pBI +
188 							ImplGetDIBColorCount( rSalBmp.mhDIB ) * sizeof( RGBQUAD );
189 
190 		if( pBIH->biBitCount == 1 )
191 		{
192 			hNewDDB = CreateBitmap( pBIH->biWidth, pBIH->biHeight, 1, 1, NULL );
193 
194 			if( hNewDDB )
195 				SetDIBits( hDC, hNewDDB, 0, pBIH->biHeight, pBits, pBI, DIB_RGB_COLORS );
196 		}
197 		else
198 			hNewDDB = CreateDIBitmap( hDC, (PBITMAPINFOHEADER) pBI, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
199 
200 		GlobalUnlock( rSalBmp.mhDIB );
201 
202 		if( hNewDDB && WIN_GetObject( hNewDDB, sizeof( BITMAP ), &aDDBInfo ) )
203 		{
204 			mhDDB = hNewDDB;
205 			maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
206 			mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
207 
208 			bRet = TRUE;
209 		}
210 		else if( hNewDDB )
211 			DeleteObject( hNewDDB );
212 	}
213 
214 	return bRet;
215 }
216 
217 // ------------------------------------------------------------------
218 
219 bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, sal_uInt16 nNewBitCount )
220 {
221 	bool bRet = FALSE;
222 
223     const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
224 
225 	if( rSalBmp.mhDDB )
226 	{
227 		mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() );
228 
229 		if( mhDIB )
230 		{
231 			PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
232 			const int	nLines = (int) rSalBmp.maSize.Height();
233 			HDC 		hDC = GetDC( 0 );
234 			PBYTE		pBits = (PBYTE) pBI + *(DWORD*) pBI +
235 								ImplGetDIBColorCount( mhDIB ) * sizeof( RGBQUAD );
236 			SalData*	pSalData = GetSalData();
237 			HPALETTE	hOldPal = 0;
238 
239 			if ( pSalData->mhDitherPal )
240 			{
241 				hOldPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
242 				RealizePalette( hDC );
243 			}
244 
245 			if( GetDIBits( hDC, rSalBmp.mhDDB, 0, nLines, pBits, pBI, DIB_RGB_COLORS ) == nLines )
246 			{
247 				GlobalUnlock( mhDIB );
248 				maSize = rSalBmp.maSize;
249 				mnBitCount = nNewBitCount;
250 				bRet = TRUE;
251 			}
252 			else
253 			{
254 				GlobalUnlock( mhDIB );
255 				GlobalFree( mhDIB );
256 				mhDIB = 0;
257 			}
258 
259 			if( hOldPal )
260 				SelectPalette( hDC, hOldPal, TRUE );
261 
262 			ReleaseDC( 0, hDC );
263 		}
264 	}
265 
266 	return bRet;
267 }
268 
269 // ------------------------------------------------------------------
270 
271 void WinSalBitmap::Destroy()
272 {
273 	if( mhDIB )
274 		GlobalFree( mhDIB );
275 	else if( mhDDB )
276 		DeleteObject( mhDDB );
277 
278 	maSize = Size();
279 	mnBitCount = 0;
280 }
281 
282 // ------------------------------------------------------------------
283 
284 sal_uInt16 WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB )
285 {
286 	sal_uInt16 nColors = 0;
287 
288 	if( hDIB )
289 	{
290 		PBITMAPINFO 		pBI = (PBITMAPINFO) GlobalLock( hDIB );
291 		PBITMAPINFOHEADER	pBIH = (PBITMAPINFOHEADER) pBI;
292 
293 		if ( pBIH->biSize != sizeof( BITMAPCOREHEADER ) )
294 		{
295 			if( pBIH->biBitCount <= 8 )
296 			{
297 				if ( pBIH->biClrUsed )
298 					nColors = (sal_uInt16) pBIH->biClrUsed;
299 				else
300 					nColors = 1 << pBIH->biBitCount;
301 			}
302 		}
303 		else if( ( (PBITMAPCOREHEADER) pBI )->bcBitCount <= 8 )
304 			nColors = 1 << ( (PBITMAPCOREHEADER) pBI )->bcBitCount;
305 
306 		GlobalUnlock( hDIB );
307 	}
308 
309 	return nColors;
310 }
311 
312 // ------------------------------------------------------------------
313 
314 HGLOBAL WinSalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rPal )
315 {
316 	DBG_ASSERT( nBits == 1 || nBits == 4 || nBits == 8 || nBits == 16 || nBits == 24, "Unsupported BitCount!" );
317 
318 	HGLOBAL hDIB = 0;
319 
320 	if ( rSize.Width() && rSize.Height() )
321 	{
322 		const sal_uLong 	nImageSize = AlignedWidth4Bytes( nBits * rSize.Width() ) * rSize.Height();
323 		const sal_uInt16	nColors = ( nBits <= 8 ) ? ( 1 << nBits ) : 0;
324 
325 		hDIB = GlobalAlloc( GHND, sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD ) + nImageSize );
326 
327 		if( hDIB )
328 		{
329 			PBITMAPINFO 		pBI = (PBITMAPINFO) GlobalLock( hDIB );
330 			PBITMAPINFOHEADER	pBIH = (PBITMAPINFOHEADER) pBI;
331 
332 			pBIH->biSize = sizeof( BITMAPINFOHEADER );
333 			pBIH->biWidth = rSize.Width();
334 			pBIH->biHeight = rSize.Height();
335 			pBIH->biPlanes = 1;
336 			pBIH->biBitCount = nBits;
337 			pBIH->biCompression = BI_RGB;
338 			pBIH->biSizeImage = nImageSize;
339 			pBIH->biXPelsPerMeter = 0;
340 			pBIH->biYPelsPerMeter = 0;
341 			pBIH->biClrUsed = 0;
342 			pBIH->biClrImportant = 0;
343 
344 			if ( nColors )
345 			{
346 				const sal_uInt16 nMinCount = Min( nColors, rPal.GetEntryCount() );
347 
348 				if( nMinCount )
349 					memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof( RGBQUAD ) );
350 			}
351 
352 			GlobalUnlock( hDIB );
353 		}
354 	}
355 
356 	return hDIB;
357 }
358 
359 // ------------------------------------------------------------------
360 
361 HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
362 {
363 	HANDLE	hCopy = 0;
364 
365 	if ( bDIB && hHdl )
366 	{
367 		const sal_uLong nSize = GlobalSize( hHdl );
368 
369 		if ( (hCopy = GlobalAlloc( GHND, nSize  )) != 0 )
370 		{
371 			memcpy( (LPSTR) GlobalLock( hCopy ), (LPSTR) GlobalLock( hHdl ), nSize );
372 
373 			GlobalUnlock( hCopy );
374 			GlobalUnlock( hHdl );
375 		}
376 	}
377 	else if ( hHdl )
378 	{
379 		BITMAP aBmp;
380 
381 		// Source-Bitmap nach Groesse befragen
382 		WIN_GetObject( hHdl, sizeof( BITMAP ), (LPSTR) &aBmp );
383 
384 		// Destination-Bitmap erzeugen
385 		if ( (hCopy = CreateBitmapIndirect( &aBmp )) != 0 )
386 		{
387 			HDC 	hBmpDC = CreateCompatibleDC( 0 );
388 			HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hHdl );
389 			HDC 	hCopyDC = CreateCompatibleDC( hBmpDC );
390 			HBITMAP hCopyOld = (HBITMAP) SelectObject( hCopyDC, hCopy );
391 
392 			BitBlt( hCopyDC, 0, 0, aBmp.bmWidth, aBmp.bmHeight, hBmpDC, 0, 0, SRCCOPY );
393 
394 			SelectObject( hCopyDC, hCopyOld );
395 			DeleteDC( hCopyDC );
396 
397 			SelectObject( hBmpDC, hBmpOld );
398 			DeleteDC( hBmpDC );
399 		}
400 	}
401 
402 	return hCopy;
403 }
404 
405 // ------------------------------------------------------------------
406 
407 BitmapBuffer* WinSalBitmap::AcquireBuffer( bool /*bReadOnly*/ )
408 {
409 	BitmapBuffer* pBuffer = NULL;
410 
411 	if( mhDIB )
412 	{
413 		PBITMAPINFO 		pBI = (PBITMAPINFO) GlobalLock( mhDIB );
414 		PBITMAPINFOHEADER	pBIH = (PBITMAPINFOHEADER) pBI;
415 
416 		if( ( pBIH->biCompression == BI_RLE4 ) || ( pBIH->biCompression == BI_RLE8 ) )
417 		{
418 			Size	aSizePix( pBIH->biWidth, pBIH->biHeight );
419 			HGLOBAL hNewDIB = ImplCreateDIB( aSizePix, pBIH->biBitCount, BitmapPalette() );
420 
421 			if( hNewDIB )
422 			{
423 				PBITMAPINFO 		pNewBI = (PBITMAPINFO) GlobalLock( hNewDIB );
424 				PBITMAPINFOHEADER	pNewBIH = (PBITMAPINFOHEADER) pNewBI;
425 				const sal_uInt16		nColorCount = ImplGetDIBColorCount( hNewDIB );
426 				const sal_uLong 		nOffset = *(DWORD*) pBI + nColorCount * sizeof( RGBQUAD );
427 				BYTE*				pOldBits = (PBYTE) pBI + nOffset;
428 				BYTE*				pNewBits = (PBYTE) pNewBI + nOffset;
429 
430 				memcpy( pNewBI, pBI, nOffset );
431 				pNewBIH->biCompression = 0;
432 				ImplDecodeRLEBuffer( pOldBits, pNewBits, aSizePix, pBIH->biCompression == BI_RLE4 );
433 
434 				GlobalUnlock( mhDIB );
435 				GlobalFree( mhDIB );
436 				mhDIB = hNewDIB;
437 				pBI = pNewBI;
438 				pBIH = pNewBIH;
439 			}
440 		}
441 
442 		if( pBIH->biPlanes == 1 )
443 		{
444 			pBuffer = new BitmapBuffer;
445 
446 			pBuffer->mnFormat = BMP_FORMAT_BOTTOM_UP |
447 								( pBIH->biBitCount == 1 ? BMP_FORMAT_1BIT_MSB_PAL :
448 								  pBIH->biBitCount == 4 ? BMP_FORMAT_4BIT_MSN_PAL :
449 								  pBIH->biBitCount == 8 ? BMP_FORMAT_8BIT_PAL :
450 								  pBIH->biBitCount == 16 ? BMP_FORMAT_16BIT_TC_LSB_MASK :
451 								  pBIH->biBitCount == 24 ? BMP_FORMAT_24BIT_TC_BGR :
452 								  pBIH->biBitCount == 32 ? BMP_FORMAT_32BIT_TC_MASK : 0UL );
453 
454 			if( BMP_SCANLINE_FORMAT( pBuffer->mnFormat ) )
455 			{
456 				pBuffer->mnWidth = maSize.Width();
457 				pBuffer->mnHeight = maSize.Height();
458 				pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->biBitCount );
459 				pBuffer->mnBitCount = (sal_uInt16) pBIH->biBitCount;
460 
461 				if( pBuffer->mnBitCount <= 8 )
462 				{
463 					const sal_uInt16 nPalCount = ImplGetDIBColorCount( mhDIB );
464 
465 					pBuffer->maPalette.SetEntryCount( nPalCount );
466 					memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->bmiColors, nPalCount * sizeof( RGBQUAD ) );
467 					pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nPalCount * sizeof( RGBQUAD );
468 				}
469 				else if( ( pBIH->biBitCount == 16 ) || ( pBIH->biBitCount == 32 ) )
470 				{
471 					sal_uLong nOffset = 0UL;
472 
473 					if( pBIH->biCompression == BI_BITFIELDS )
474 					{
475 						nOffset = 3 * sizeof( RGBQUAD );
476 						pBuffer->maColorMask = ColorMask( *(UINT32*) &pBI->bmiColors[ 0 ],
477 														  *(UINT32*) &pBI->bmiColors[ 1 ],
478 														  *(UINT32*) &pBI->bmiColors[ 2 ] );
479 					}
480 					else if( pBIH->biBitCount == 16 )
481 						pBuffer->maColorMask = ColorMask( 0x00007c00UL, 0x000003e0UL, 0x0000001fUL );
482 					else
483 						pBuffer->maColorMask = ColorMask( 0x00ff0000UL, 0x0000ff00UL, 0x000000ffUL );
484 
485 					pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nOffset;
486 				}
487 				else
488 					pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI;
489 			}
490 			else
491 			{
492 				GlobalUnlock( mhDIB );
493 				delete pBuffer;
494 				pBuffer = NULL;
495 			}
496 		}
497 		else
498 			GlobalUnlock( mhDIB );
499 	}
500 
501 	return pBuffer;
502 }
503 
504 // ------------------------------------------------------------------
505 
506 void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
507 {
508 	if( pBuffer )
509 	{
510 		if( mhDIB )
511 		{
512 			if( !bReadOnly && !!pBuffer->maPalette )
513 			{
514 				PBITMAPINFO 	pBI = (PBITMAPINFO) GlobalLock( mhDIB );
515 				const sal_uInt16	nCount = pBuffer->maPalette.GetEntryCount();
516 				const sal_uInt16	nDIBColorCount = ImplGetDIBColorCount( mhDIB );
517 				memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), Min( nDIBColorCount, nCount ) * sizeof( RGBQUAD ) );
518 				GlobalUnlock( mhDIB );
519 			}
520 
521 			GlobalUnlock( mhDIB );
522 		}
523 
524 		delete pBuffer;
525 	}
526 }
527 
528 // ------------------------------------------------------------------
529 
530 void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
531 									 const Size& rSizePixel, bool bRLE4 )
532 {
533 	HPBYTE			pRLE = (HPBYTE) pSrcBuf;
534 	HPBYTE			pDIB = (HPBYTE) pDstBuf;
535 	HPBYTE			pRow = (HPBYTE) pDstBuf;
536 	sal_uLong			nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) );
537 	HPBYTE			pLast = pDIB + rSizePixel.Height() * nWidthAl - 1;
538 	sal_uLong			nCountByte;
539 	sal_uLong			nRunByte;
540 	sal_uLong			nX = 0;
541 	sal_uLong			i;
542 	BYTE			cTmp;
543 	bool			bEndDecoding = FALSE;
544 
545 	if( pRLE && pDIB )
546 	{
547 		do
548 		{
549 			if( ( nCountByte = *pRLE++ ) == 0 )
550 			{
551 				nRunByte = *pRLE++;
552 
553 				if( nRunByte > 2UL )
554 				{
555 					if( bRLE4 )
556 					{
557 						nCountByte = nRunByte >> 1UL;
558 
559 						for( i = 0; i < nCountByte; i++ )
560 						{
561 							cTmp = *pRLE++;
562 							ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
563 							ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
564 						}
565 
566 						if( nRunByte & 1 )
567 							ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
568 
569 						if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
570 							pRLE++;
571 					}
572 					else
573 					{
574 						memcpy( &pDIB[ nX ], pRLE, nRunByte );
575 						pRLE += nRunByte;
576 						nX += nRunByte;
577 
578 						if( nRunByte & 1 )
579 							pRLE++;
580 					}
581 				}
582 				else if( !nRunByte )
583 				{
584 					pDIB = ( pRow += nWidthAl );
585 					nX = 0UL;
586 				}
587 				else if( nRunByte == 1 )
588 					bEndDecoding = TRUE;
589 				else
590 				{
591 					nX += *pRLE++;
592 					pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
593 				}
594 			}
595 			else
596 			{
597 				cTmp = *pRLE++;
598 
599 				if( bRLE4 )
600 				{
601 					nRunByte = nCountByte >> 1;
602 
603 					for( i = 0; i < nRunByte; i++ )
604 					{
605 						ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
606 						ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
607 					}
608 
609 					if( nCountByte & 1 )
610 						ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
611 				}
612 				else
613 				{
614 					for( i = 0; i < nCountByte; i++ )
615 						pDIB[ nX++ ] = cTmp;
616 				}
617 			}
618 		}
619 		while( !bEndDecoding && ( pDIB <= pLast ) );
620 	}
621 }
622 
623 bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
624 {
625     bool bRet = false;
626     if( mhDIB || mhDDB )
627     {
628         bRet = true;
629         rData.pDIB = mhDIB;
630         rData.pDDB = mhDDB;
631         const Size& rSize = GetSize ();
632         rData.mnWidth = rSize.Width();
633         rData.mnHeight = rSize.Height();
634     }
635     return bRet;
636 }
637