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