xref: /AOO41X/main/vcl/win/source/gdi/salbmp.cxx (revision 03c97e340010506c11d4ffaab7f577e5f7050fe6)
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() && rSize.Height() )
317     {
318         const sal_uLong     nImageSize = AlignedWidth4Bytes( nBits * rSize.Width() ) * rSize.Height();
319         const sal_uInt16    nColors = ( nBits <= 8 ) ? ( 1 << nBits ) : 0;
320 
321         hDIB = GlobalAlloc( GHND, sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD ) + nImageSize );
322 
323         if( hDIB )
324         {
325             PBITMAPINFO         pBI = (PBITMAPINFO) GlobalLock( hDIB );
326             PBITMAPINFOHEADER   pBIH = (PBITMAPINFOHEADER) pBI;
327 
328             pBIH->biSize = sizeof( BITMAPINFOHEADER );
329             pBIH->biWidth = rSize.Width();
330             pBIH->biHeight = rSize.Height();
331             pBIH->biPlanes = 1;
332             pBIH->biBitCount = nBits;
333             pBIH->biCompression = BI_RGB;
334             pBIH->biSizeImage = nImageSize;
335             pBIH->biXPelsPerMeter = 0;
336             pBIH->biYPelsPerMeter = 0;
337             pBIH->biClrUsed = 0;
338             pBIH->biClrImportant = 0;
339 
340             if ( nColors )
341             {
342                 const sal_uInt16 nMinCount = Min( nColors, rPal.GetEntryCount() );
343 
344                 if( nMinCount )
345                     memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof( RGBQUAD ) );
346             }
347 
348             GlobalUnlock( hDIB );
349         }
350     }
351 
352     return hDIB;
353 }
354 
355 // ------------------------------------------------------------------
356 
357 HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
358 {
359     HANDLE  hCopy = 0;
360 
361     if ( bDIB && hHdl )
362     {
363         const sal_uLong nSize = GlobalSize( hHdl );
364 
365         if ( (hCopy = GlobalAlloc( GHND, nSize  )) != 0 )
366         {
367             memcpy( (LPSTR) GlobalLock( hCopy ), (LPSTR) GlobalLock( hHdl ), nSize );
368 
369             GlobalUnlock( hCopy );
370             GlobalUnlock( hHdl );
371         }
372     }
373     else if ( hHdl )
374     {
375         BITMAP aBmp;
376 
377         // Source-Bitmap nach Groesse befragen
378         WIN_GetObject( hHdl, sizeof( BITMAP ), (LPSTR) &aBmp );
379 
380         // Destination-Bitmap erzeugen
381         if ( (hCopy = CreateBitmapIndirect( &aBmp )) != 0 )
382         {
383             HDC     hBmpDC = CreateCompatibleDC( 0 );
384             HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hHdl );
385             HDC     hCopyDC = CreateCompatibleDC( hBmpDC );
386             HBITMAP hCopyOld = (HBITMAP) SelectObject( hCopyDC, hCopy );
387 
388             BitBlt( hCopyDC, 0, 0, aBmp.bmWidth, aBmp.bmHeight, hBmpDC, 0, 0, SRCCOPY );
389 
390             SelectObject( hCopyDC, hCopyOld );
391             DeleteDC( hCopyDC );
392 
393             SelectObject( hBmpDC, hBmpOld );
394             DeleteDC( hBmpDC );
395         }
396     }
397 
398     return hCopy;
399 }
400 
401 // ------------------------------------------------------------------
402 
403 BitmapBuffer* WinSalBitmap::AcquireBuffer( bool /*bReadOnly*/ )
404 {
405     BitmapBuffer* pBuffer = NULL;
406 
407     if( mhDIB )
408     {
409         PBITMAPINFO         pBI = (PBITMAPINFO) GlobalLock( mhDIB );
410         PBITMAPINFOHEADER   pBIH = (PBITMAPINFOHEADER) pBI;
411 
412         if( ( pBIH->biCompression == BI_RLE4 ) || ( pBIH->biCompression == BI_RLE8 ) )
413         {
414             Size    aSizePix( pBIH->biWidth, pBIH->biHeight );
415             HGLOBAL hNewDIB = ImplCreateDIB( aSizePix, pBIH->biBitCount, BitmapPalette() );
416 
417             if( hNewDIB )
418             {
419                 PBITMAPINFO         pNewBI = (PBITMAPINFO) GlobalLock( hNewDIB );
420                 PBITMAPINFOHEADER   pNewBIH = (PBITMAPINFOHEADER) pNewBI;
421                 const sal_uInt16        nColorCount = ImplGetDIBColorCount( hNewDIB );
422                 const sal_uLong         nOffset = *(DWORD*) pBI + nColorCount * sizeof( RGBQUAD );
423                 BYTE*               pOldBits = (PBYTE) pBI + nOffset;
424                 BYTE*               pNewBits = (PBYTE) pNewBI + nOffset;
425 
426                 memcpy( pNewBI, pBI, nOffset );
427                 pNewBIH->biCompression = 0;
428                 ImplDecodeRLEBuffer( pOldBits, pNewBits, aSizePix, pBIH->biCompression == BI_RLE4 );
429 
430                 GlobalUnlock( mhDIB );
431                 GlobalFree( mhDIB );
432                 mhDIB = hNewDIB;
433                 pBI = pNewBI;
434                 pBIH = pNewBIH;
435             }
436         }
437 
438         if( pBIH->biPlanes == 1 )
439         {
440             pBuffer = new BitmapBuffer;
441 
442             pBuffer->mnFormat = BMP_FORMAT_BOTTOM_UP |
443                                 ( pBIH->biBitCount == 1 ? BMP_FORMAT_1BIT_MSB_PAL :
444                                   pBIH->biBitCount == 4 ? BMP_FORMAT_4BIT_MSN_PAL :
445                                   pBIH->biBitCount == 8 ? BMP_FORMAT_8BIT_PAL :
446                                   pBIH->biBitCount == 16 ? BMP_FORMAT_16BIT_TC_LSB_MASK :
447                                   pBIH->biBitCount == 24 ? BMP_FORMAT_24BIT_TC_BGR :
448                                   pBIH->biBitCount == 32 ? BMP_FORMAT_32BIT_TC_MASK : 0UL );
449 
450             if( BMP_SCANLINE_FORMAT( pBuffer->mnFormat ) )
451             {
452                 pBuffer->mnWidth = maSize.Width();
453                 pBuffer->mnHeight = maSize.Height();
454                 pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->biBitCount );
455                 pBuffer->mnBitCount = (sal_uInt16) pBIH->biBitCount;
456 
457                 if( pBuffer->mnBitCount <= 8 )
458                 {
459                     const sal_uInt16 nPalCount = ImplGetDIBColorCount( mhDIB );
460 
461                     pBuffer->maPalette.SetEntryCount( nPalCount );
462                     memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->bmiColors, nPalCount * sizeof( RGBQUAD ) );
463                     pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nPalCount * sizeof( RGBQUAD );
464                 }
465                 else if( ( pBIH->biBitCount == 16 ) || ( pBIH->biBitCount == 32 ) )
466                 {
467                     sal_uLong nOffset = 0UL;
468 
469                     if( pBIH->biCompression == BI_BITFIELDS )
470                     {
471                         nOffset = 3 * sizeof( RGBQUAD );
472                         pBuffer->maColorMask = ColorMask( *(UINT32*) &pBI->bmiColors[ 0 ],
473                                                           *(UINT32*) &pBI->bmiColors[ 1 ],
474                                                           *(UINT32*) &pBI->bmiColors[ 2 ] );
475                     }
476                     else if( pBIH->biBitCount == 16 )
477                         pBuffer->maColorMask = ColorMask( 0x00007c00UL, 0x000003e0UL, 0x0000001fUL );
478                     else
479                         pBuffer->maColorMask = ColorMask( 0x00ff0000UL, 0x0000ff00UL, 0x000000ffUL );
480 
481                     pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nOffset;
482                 }
483                 else
484                     pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI;
485             }
486             else
487             {
488                 GlobalUnlock( mhDIB );
489                 delete pBuffer;
490                 pBuffer = NULL;
491             }
492         }
493         else
494             GlobalUnlock( mhDIB );
495     }
496 
497     return pBuffer;
498 }
499 
500 // ------------------------------------------------------------------
501 
502 void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
503 {
504     if( pBuffer )
505     {
506         if( mhDIB )
507         {
508             if( !bReadOnly && !!pBuffer->maPalette )
509             {
510                 PBITMAPINFO     pBI = (PBITMAPINFO) GlobalLock( mhDIB );
511                 const sal_uInt16    nCount = pBuffer->maPalette.GetEntryCount();
512                 const sal_uInt16    nDIBColorCount = ImplGetDIBColorCount( mhDIB );
513                 memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), Min( nDIBColorCount, nCount ) * sizeof( RGBQUAD ) );
514                 GlobalUnlock( mhDIB );
515             }
516 
517             GlobalUnlock( mhDIB );
518         }
519 
520         delete pBuffer;
521     }
522 }
523 
524 // ------------------------------------------------------------------
525 
526 void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
527                                      const Size& rSizePixel, bool bRLE4 )
528 {
529     HPBYTE          pRLE = (HPBYTE) pSrcBuf;
530     HPBYTE          pDIB = (HPBYTE) pDstBuf;
531     HPBYTE          pRow = (HPBYTE) pDstBuf;
532     sal_uLong           nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) );
533     HPBYTE          pLast = pDIB + rSizePixel.Height() * nWidthAl - 1;
534     sal_uLong           nCountByte;
535     sal_uLong           nRunByte;
536     sal_uLong           nX = 0;
537     sal_uLong           i;
538     BYTE            cTmp;
539     bool            bEndDecoding = FALSE;
540 
541     if( pRLE && pDIB )
542     {
543         do
544         {
545             if( ( nCountByte = *pRLE++ ) == 0 )
546             {
547                 nRunByte = *pRLE++;
548 
549                 if( nRunByte > 2UL )
550                 {
551                     if( bRLE4 )
552                     {
553                         nCountByte = nRunByte >> 1UL;
554 
555                         for( i = 0; i < nCountByte; i++ )
556                         {
557                             cTmp = *pRLE++;
558                             ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
559                             ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
560                         }
561 
562                         if( nRunByte & 1 )
563                             ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
564 
565                         if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
566                             pRLE++;
567                     }
568                     else
569                     {
570                         memcpy( &pDIB[ nX ], pRLE, nRunByte );
571                         pRLE += nRunByte;
572                         nX += nRunByte;
573 
574                         if( nRunByte & 1 )
575                             pRLE++;
576                     }
577                 }
578                 else if( !nRunByte )
579                 {
580                     pDIB = ( pRow += nWidthAl );
581                     nX = 0UL;
582                 }
583                 else if( nRunByte == 1 )
584                     bEndDecoding = TRUE;
585                 else
586                 {
587                     nX += *pRLE++;
588                     pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
589                 }
590             }
591             else
592             {
593                 cTmp = *pRLE++;
594 
595                 if( bRLE4 )
596                 {
597                     nRunByte = nCountByte >> 1;
598 
599                     for( i = 0; i < nRunByte; i++ )
600                     {
601                         ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
602                         ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
603                     }
604 
605                     if( nCountByte & 1 )
606                         ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
607                 }
608                 else
609                 {
610                     for( i = 0; i < nCountByte; i++ )
611                         pDIB[ nX++ ] = cTmp;
612                 }
613             }
614         }
615         while( !bEndDecoding && ( pDIB <= pLast ) );
616     }
617 }
618 
619 bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
620 {
621     bool bRet = false;
622     if( mhDIB || mhDDB )
623     {
624         bRet = true;
625         rData.pDIB = mhDIB;
626         rData.pDDB = mhDDB;
627         const Size& rSize = GetSize ();
628         rData.mnWidth = rSize.Width();
629         rData.mnHeight = rSize.Height();
630     }
631     return bRet;
632 }
633