xref: /trunk/main/vcl/unx/generic/gdi/salbmp.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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 <string.h>
32 #include <stdio.h>
33 #include <errno.h>
34 #ifdef FREEBSD
35 #include <sys/types.h>
36 #endif
37 
38 #include <osl/endian.h>
39 #include <rtl/memory.h>
40 
41 #include <vcl/bitmap.hxx>
42 #include <vcl/salbtype.hxx>
43 
44 #include <tools/prex.h>
45 #include "unx/Xproto.h"
46 #include <tools/postx.h>
47 #include <unx/salunx.h>
48 #include <unx/saldata.hxx>
49 #include <unx/saldisp.hxx>
50 #include <unx/salgdi.h>
51 #include <unx/salbmp.h>
52 #include <unx/salinst.h>
53 
54 // -----------
55 // - Defines -
56 // -----------
57 
58 #define SAL_DRAWPIXMAP_MAX_EXT 4096
59 
60 // -------------
61 // - SalBitmap -
62 // -------------
63 
64 SalBitmap* X11SalInstance::CreateSalBitmap()
65 {
66     return new X11SalBitmap();
67 }
68 
69 ImplSalBitmapCache* X11SalBitmap::mpCache = NULL;
70 sal_uLong               X11SalBitmap::mnCacheInstCount = 0;
71 
72 // -----------------------------------------------------------------------------
73 
74 X11SalBitmap::X11SalBitmap() :
75     mpDIB( NULL ),
76     mpDDB( NULL )
77 {
78 }
79 
80 // -----------------------------------------------------------------------------
81 
82 X11SalBitmap::~X11SalBitmap()
83 {
84     Destroy();
85 }
86 
87 // -----------------------------------------------------------------------------
88 
89 void X11SalBitmap::ImplCreateCache()
90 {
91     if( !mnCacheInstCount++ )
92         mpCache = new ImplSalBitmapCache;
93 }
94 
95 // -----------------------------------------------------------------------------
96 
97 void X11SalBitmap::ImplDestroyCache()
98 {
99     DBG_ASSERT( mnCacheInstCount, "X11SalBitmap::ImplDestroyCache(): underflow" );
100 
101     if( mnCacheInstCount && !--mnCacheInstCount )
102         delete mpCache, mpCache = NULL;
103 }
104 
105 // -----------------------------------------------------------------------------
106 
107 void X11SalBitmap::ImplRemovedFromCache()
108 {
109     if( mpDDB )
110         delete mpDDB, mpDDB = NULL;
111 }
112 
113 // -----------------------------------------------------------------------------
114 
115 BitmapBuffer* X11SalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
116 {
117     DBG_ASSERT( nBitCount == 1 || nBitCount == 4 || nBitCount == 8 || nBitCount == 16 || nBitCount == 24, "Unsupported BitCount!" );
118 
119     BitmapBuffer* pDIB = NULL;
120 
121     if( rSize.Width() && rSize.Height() )
122     {
123         try
124         {
125             pDIB = new BitmapBuffer;
126         }
127         catch( std::bad_alloc& )
128         {
129             pDIB = NULL;
130         }
131 
132         if( pDIB )
133         {
134             const sal_uInt16 nColors = ( nBitCount <= 8 ) ? ( 1 << nBitCount ) : 0;
135 
136             pDIB->mnFormat = BMP_FORMAT_BOTTOM_UP;
137 
138             switch( nBitCount )
139             {
140                 case( 1 ): pDIB->mnFormat |= BMP_FORMAT_1BIT_MSB_PAL; break;
141                 case( 4 ): pDIB->mnFormat |= BMP_FORMAT_4BIT_MSN_PAL; break;
142                 case( 8 ): pDIB->mnFormat |= BMP_FORMAT_8BIT_PAL; break;
143 #ifdef OSL_BIGENDIAN
144                 case(16 ):
145                     pDIB->mnFormat|= BMP_FORMAT_16BIT_TC_MSB_MASK;
146                     pDIB->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f );
147                     break;
148 #else
149                 case(16 ):
150                     pDIB->mnFormat|= BMP_FORMAT_16BIT_TC_LSB_MASK;
151                     pDIB->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f );
152                     break;
153 #endif
154                 default:
155                     nBitCount = 24;
156                     //fall through
157                 case 24:
158                     pDIB->mnFormat |= BMP_FORMAT_24BIT_TC_BGR;
159                 break;
160             }
161 
162             pDIB->mnWidth = rSize.Width();
163             pDIB->mnHeight = rSize.Height();
164             pDIB->mnScanlineSize = AlignedWidth4Bytes( pDIB->mnWidth * nBitCount );
165             pDIB->mnBitCount = nBitCount;
166 
167             if( nColors )
168             {
169                 pDIB->maPalette = rPal;
170                 pDIB->maPalette.SetEntryCount( nColors );
171             }
172 
173             try
174             {
175                 pDIB->mpBits = new sal_uInt8[ pDIB->mnScanlineSize * pDIB->mnHeight ];
176             }
177             catch(std::bad_alloc&)
178             {
179                 delete pDIB;
180                 pDIB = NULL;
181             }
182         }
183     }
184     else
185         pDIB = NULL;
186 
187     return pDIB;
188 }
189 
190 // -----------------------------------------------------------------------------
191 
192 BitmapBuffer* X11SalBitmap::ImplCreateDIB( Drawable aDrawable,
193                                            int nScreen,
194                                            long nDrawableDepth,
195                                            long nX, long nY,
196                                            long nWidth, long nHeight )
197 {
198     BitmapBuffer* pDIB = NULL;
199 
200     if( aDrawable && nWidth && nHeight && nDrawableDepth )
201     {
202         SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
203         SalXLib*    pXLib = pSalDisp->GetXLib();
204         Display*    pXDisp = pSalDisp->GetDisplay();
205 
206         // do not die on XError here
207         // alternatively one could check the coordinates for being offscreen
208         // but this call can actually work on servers with backing store
209         // defaults even if the rectangle is offscreen
210         // so better catch the XError
211         pXLib->PushXErrorLevel( true );
212         XImage* pImage = XGetImage( pXDisp, aDrawable, nX, nY, nWidth, nHeight, AllPlanes, ZPixmap );
213         bool bWasError = pXLib->HasXErrorOccured() && pXLib->GetLastXErrorRequestCode() == X_GetImage;
214         pXLib->PopXErrorLevel();
215 
216         if( ! bWasError && pImage && pImage->data )
217         {
218             const SalTwoRect        aTwoRect = { 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight };
219             BitmapBuffer            aSrcBuf;
220             sal_uLong                   nDstFormat = BMP_FORMAT_BOTTOM_UP;
221             const BitmapPalette*    pDstPal = NULL;
222 
223             aSrcBuf.mnFormat = BMP_FORMAT_TOP_DOWN;
224             aSrcBuf.mnWidth = nWidth;
225             aSrcBuf.mnHeight = nHeight;
226             aSrcBuf.mnBitCount = pImage->bits_per_pixel;
227             aSrcBuf.mnScanlineSize = pImage->bytes_per_line;
228             aSrcBuf.mpBits = (sal_uInt8*) pImage->data;
229 
230             pImage->red_mask = pSalDisp->GetVisual( nScreen ).red_mask;
231             pImage->green_mask = pSalDisp->GetVisual( nScreen ).green_mask;
232             pImage->blue_mask = pSalDisp->GetVisual( nScreen ).blue_mask;
233 
234             switch( aSrcBuf.mnBitCount )
235             {
236                 case( 1 ):
237                 {
238                     aSrcBuf.mnFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_1BIT_LSB_PAL : BMP_FORMAT_1BIT_MSB_PAL );
239                     nDstFormat |= BMP_FORMAT_1BIT_MSB_PAL;
240                 }
241                 break;
242 
243                 case( 4 ):
244                 {
245                     aSrcBuf.mnFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_4BIT_LSN_PAL : BMP_FORMAT_4BIT_MSN_PAL );
246                     nDstFormat |= BMP_FORMAT_4BIT_MSN_PAL;
247                 }
248                 break;
249 
250                 case( 8 ):
251                 {
252                     aSrcBuf.mnFormat |= BMP_FORMAT_8BIT_PAL;
253                     nDstFormat |= BMP_FORMAT_8BIT_PAL;
254                 }
255                 break;
256 
257                 case( 16 ):
258                 {
259                     nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
260                     aSrcBuf.maColorMask = ColorMask( pImage->red_mask, pImage->green_mask, pImage->blue_mask );
261 
262                     if( LSBFirst == pImage->byte_order )
263                     {
264                         aSrcBuf.mnFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK;
265                     }
266                     else
267                     {
268                         aSrcBuf.mnFormat |= BMP_FORMAT_16BIT_TC_MSB_MASK;
269                         // aSrcBuf.maColorMask = ColorMask( pImage->red_mask ), SWAPSHORT( pImage->green_mask ), SWAPSHORT( pImage->blue_mask ) );
270                     }
271                 }
272                 break;
273 
274                 case( 24 ):
275                 {
276                     if( ( LSBFirst == pImage->byte_order ) && ( pImage->red_mask == 0xFF ) )
277                         aSrcBuf.mnFormat |= BMP_FORMAT_24BIT_TC_RGB;
278                     else
279                         aSrcBuf.mnFormat |= BMP_FORMAT_24BIT_TC_BGR;
280 
281                     nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
282                 }
283                 break;
284 
285                 case( 32 ):
286                 {
287                     if( LSBFirst == pImage->byte_order )
288                         aSrcBuf.mnFormat |= (  pSalDisp->GetVisual(nScreen).red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_RGBA : BMP_FORMAT_32BIT_TC_BGRA );
289                     else
290                         aSrcBuf.mnFormat |= (  pSalDisp->GetVisual(nScreen).red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_ABGR : BMP_FORMAT_32BIT_TC_ARGB );
291 
292                     nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
293                 }
294                 break;
295             }
296 
297             BitmapPalette& rPal = aSrcBuf.maPalette;
298 
299             if( aSrcBuf.mnBitCount == 1 )
300             {
301                 rPal.SetEntryCount( 2 );
302                 pDstPal = &rPal;
303 
304                 rPal[ 0 ] = Color( COL_BLACK );
305                 rPal[ 1 ] = Color( COL_WHITE );
306             }
307             else if( aSrcBuf.mnBitCount <= 8 )
308             {
309                 const SalColormap& rColMap = pSalDisp->GetColormap( nScreen );
310                 const sal_uInt16 nCols = Min( (sal_uLong)rColMap.GetUsed(), (sal_uLong)(1 << nDrawableDepth) );
311 
312                 rPal.SetEntryCount( nCols );
313                 pDstPal = &rPal;
314 
315                 for( sal_uInt16 i = 0; i < nCols; i++ )
316                 {
317                     const SalColor  nColor( rColMap.GetColor( i ) );
318                     BitmapColor&    rBmpCol = rPal[ i ];
319 
320                     rBmpCol.SetRed( SALCOLOR_RED( nColor ) );
321                     rBmpCol.SetGreen( SALCOLOR_GREEN( nColor ) );
322                     rBmpCol.SetBlue( SALCOLOR_BLUE( nColor ) );
323                 }
324             }
325 
326             nDstFormat = aSrcBuf.mnFormat;
327             pDIB = StretchAndConvert( aSrcBuf, aTwoRect, nDstFormat,
328                 const_cast<BitmapPalette*>(pDstPal), &aSrcBuf.maColorMask );
329             XDestroyImage( pImage );
330         }
331     }
332 
333     return pDIB;
334 }
335 
336 // -----------------------------------------------------------------------------
337 
338 XImage* X11SalBitmap::ImplCreateXImage( SalDisplay *pSalDisp, int nScreen, long nDepth, const SalTwoRect& rTwoRect ) const
339 {
340     XImage* pImage = NULL;
341 
342     if( !mpDIB && mpDDB )
343     {
344         const_cast<X11SalBitmap*>(this)->mpDIB =
345             ImplCreateDIB( mpDDB->ImplGetPixmap(),
346                            mpDDB->ImplGetScreen(),
347                            mpDDB->ImplGetDepth(),
348                            0, 0,
349                            mpDDB->ImplGetWidth(),
350                            mpDDB->ImplGetHeight() );
351     }
352 
353     if( mpDIB && mpDIB->mnWidth && mpDIB->mnHeight )
354     {
355         Display*    pXDisp = pSalDisp->GetDisplay();
356         long        nWidth = rTwoRect.mnDestWidth;
357         long        nHeight = rTwoRect.mnDestHeight;
358 
359         if( 1 == GetBitCount() )
360             nDepth = 1;
361 
362         pImage = XCreateImage( pXDisp, pSalDisp->GetVisual( nScreen ).GetVisual(),
363                                nDepth, ( 1 == nDepth ) ? XYBitmap :ZPixmap, 0, NULL,
364                                nWidth, nHeight, 32, 0 );
365 
366         if( pImage )
367         {
368             BitmapBuffer*   pDstBuf;
369             sal_uLong           nDstFormat = BMP_FORMAT_TOP_DOWN;
370             BitmapPalette*  pPal = NULL;
371             ColorMask*      pMask = NULL;
372 
373             switch( pImage->bits_per_pixel )
374             {
375                 case( 1 ):
376                     nDstFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_1BIT_LSB_PAL : BMP_FORMAT_1BIT_MSB_PAL );
377                 break;
378 
379                 case( 4 ):
380                     nDstFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_4BIT_LSN_PAL : BMP_FORMAT_4BIT_MSN_PAL );
381                 break;
382 
383                 case( 8 ):
384                     nDstFormat |= BMP_FORMAT_8BIT_PAL;
385                 break;
386 
387                 case( 16 ):
388                 {
389                     #ifdef OSL_BIGENDIAN
390 
391                     if( MSBFirst == pImage->byte_order )
392                         nDstFormat |= BMP_FORMAT_16BIT_TC_MSB_MASK;
393                     else
394                         nDstFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK;
395 
396                     #else /* OSL_LITENDIAN */
397 
398                     nDstFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK;
399                     if( MSBFirst == pImage->byte_order )
400                         pImage->byte_order = LSBFirst;
401 
402                     #endif
403 
404                     pMask = new ColorMask( pImage->red_mask, pImage->green_mask, pImage->blue_mask );
405                 }
406                 break;
407 
408                 case( 24 ):
409                 {
410                     if( ( LSBFirst == pImage->byte_order ) && ( pImage->red_mask == 0xFF ) )
411                         nDstFormat |= BMP_FORMAT_24BIT_TC_RGB;
412                     else
413                         nDstFormat |= BMP_FORMAT_24BIT_TC_BGR;
414                 }
415                 break;
416 
417                 case( 32 ):
418                 {
419                     if( LSBFirst == pImage->byte_order )
420                         nDstFormat |= ( pImage->red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_RGBA : BMP_FORMAT_32BIT_TC_BGRA );
421                     else
422                         nDstFormat |= ( pImage->red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_ABGR : BMP_FORMAT_32BIT_TC_ARGB );
423                 }
424                 break;
425             }
426 
427             if( pImage->depth == 1 )
428             {
429                 pPal = new BitmapPalette( 2 );
430                 (*pPal)[ 0 ] = Color( COL_BLACK );
431                 (*pPal)[ 1 ] = Color( COL_WHITE );
432             }
433             else if( pImage->depth <= 8 )
434             {
435                 const SalColormap& rColMap = pSalDisp->GetColormap( nScreen );
436                 const sal_uInt16 nCols = Min( (sal_uLong)rColMap.GetUsed(), (sal_uLong)(1 << pImage->depth) );
437 
438                 pPal = new BitmapPalette( nCols );
439 
440                 for( sal_uInt16 i = 0; i < nCols; i++ )
441                 {
442                     const SalColor  nColor( rColMap.GetColor( i ) );
443                     BitmapColor&    rBmpCol = (*pPal)[ i ];
444 
445                     rBmpCol.SetRed( SALCOLOR_RED( nColor ) );
446                     rBmpCol.SetGreen( SALCOLOR_GREEN( nColor ) );
447                     rBmpCol.SetBlue( SALCOLOR_BLUE( nColor ) );
448                 }
449             }
450 
451             pDstBuf = StretchAndConvert( *mpDIB, rTwoRect, nDstFormat, pPal, pMask );
452             delete pPal;
453             delete pMask;
454 
455             if( pDstBuf && pDstBuf->mpBits )
456             {
457                 // set data in buffer as data member in pImage
458                 pImage->data = (char*) pDstBuf->mpBits;
459 
460                 // destroy buffer; don't destroy allocated data in buffer
461                 delete pDstBuf;
462             }
463             else
464             {
465                 XDestroyImage( pImage );
466                 pImage = NULL;
467             }
468         }
469     }
470 
471     return pImage;
472 }
473 
474 // -----------------------------------------------------------------------------
475 bool X11SalBitmap::ImplCreateFromDrawable( Drawable aDrawable,
476                                            int nScreen, long nDrawableDepth,
477                                            long nX, long nY, long nWidth, long nHeight )
478 {
479     Destroy();
480 
481     if( aDrawable && nWidth && nHeight && nDrawableDepth )
482         mpDDB = new ImplSalDDB( aDrawable, nScreen, nDrawableDepth, nX, nY, nWidth, nHeight );
483 
484     return( mpDDB != NULL );
485 }
486 // -----------------------------------------------------------------------------
487 
488 bool
489 X11SalBitmap::SnapShot (Display* pDisplay, XLIB_Window hWindow)
490 {
491     if (hWindow != None)
492     {
493         XWindowAttributes aAttribute;
494         XGetWindowAttributes (pDisplay, hWindow, &aAttribute);
495         if (aAttribute.map_state == IsViewable)
496         {
497             // get coordinates relative to root window
498             XLIB_Window hPetitFleur;
499             int nRootX, nRootY;
500 
501             if (XTranslateCoordinates (pDisplay, hWindow, aAttribute.root,
502                                        0, 0, &nRootX, &nRootY, &hPetitFleur))
503             {
504                 XWindowAttributes aRootAttribute;
505                 XGetWindowAttributes (pDisplay, aAttribute.root, &aRootAttribute);
506 
507                 int width  = aAttribute.width;
508                 int height = aAttribute.height;
509                 int x      = nRootX;
510                 int y      = nRootY;
511 
512                 // horizontal range check
513                 if (x < 0)
514                 {
515                     width  = width + x;
516                     x      = 0;
517                 }
518                 else
519                 if (x > aRootAttribute.width)
520                 {
521                     width = 0;
522                     x     = aRootAttribute.width;
523                 }
524                 else
525                 if (x + width > aRootAttribute.width)
526                 {
527                     width = aRootAttribute.width - x;
528                 }
529 
530                 // vertical range check
531                 if (y < 0)
532                 {
533                     height = height + y;
534                     y      = 0;
535                 }
536                 else
537                 if (y > aRootAttribute.height)
538                 {
539                     height = 0;
540                     y      = aRootAttribute.height;
541                 }
542                 else
543                 if (y + height > aRootAttribute.height)
544                 {
545                     height = aRootAttribute.height - y;
546                 }
547 
548                 if ((width > 0) && (height > 0))
549                 {
550                     XImage* pImage = XGetImage( pDisplay, aAttribute.root,
551                                                 x, y, width, height, AllPlanes, ZPixmap );
552                     bool bSnapShot = ImplCreateFromXImage( pDisplay,
553                                                            aAttribute.root,
554                                                            XScreenNumberOfScreen( aAttribute.screen ),
555                                                            pImage );
556                     XDestroyImage (pImage);
557 
558                     return bSnapShot;
559                 }
560             }
561         }
562     }
563 
564     return False;
565 }
566 
567 bool
568 X11SalBitmap::ImplCreateFromXImage (Display* pDisplay, XLIB_Window hWindow, int nScreen, XImage* pImage)
569 {
570     Destroy();
571 
572     if (pImage != NULL && pImage->width != 0 && pImage->height != 0 && pImage->depth != 0)
573     {
574         mpDDB = new ImplSalDDB (pDisplay, hWindow, nScreen, pImage);
575         return True;
576     }
577     return False;
578 }
579 
580 ImplSalDDB* X11SalBitmap::ImplGetDDB( Drawable          aDrawable,
581                                       int               nScreen,
582                                       long              nDrawableDepth,
583                                       const SalTwoRect& rTwoRect ) const
584 {
585     if( !mpDDB || !mpDDB->ImplMatches( nScreen, nDrawableDepth, rTwoRect ) )
586     {
587         if( mpDDB )
588         {
589             // do we already have a DIB? if not, create aDIB from current DDB first
590             if( !mpDIB )
591             {
592                 const_cast<X11SalBitmap*>(this)->mpDIB = ImplCreateDIB( mpDDB->ImplGetPixmap(),
593                                                                         mpDDB->ImplGetScreen(),
594                                                                         mpDDB->ImplGetDepth(),
595                                                                         0, 0,
596                                                                         mpDDB->ImplGetWidth(),
597                                                                         mpDDB->ImplGetHeight() );
598             }
599 
600             delete mpDDB, const_cast<X11SalBitmap*>(this)->mpDDB = NULL;
601         }
602 
603         if( mpCache )
604             mpCache->ImplRemove( const_cast<X11SalBitmap*>(this) );
605 
606         SalTwoRect aTwoRect( rTwoRect );
607         if( aTwoRect.mnSrcX < 0 )
608         {
609             aTwoRect.mnSrcWidth += aTwoRect.mnSrcX;
610             aTwoRect.mnSrcX = 0;
611         }
612         if( aTwoRect.mnSrcY < 0 )
613         {
614             aTwoRect.mnSrcHeight += aTwoRect.mnSrcY;
615             aTwoRect.mnSrcY = 0;
616         }
617 
618         // create new DDB from DIB
619         const Size aSize( GetSize() );
620         if( aTwoRect.mnSrcWidth == aTwoRect.mnDestWidth &&
621             aTwoRect.mnSrcHeight == aTwoRect.mnDestHeight )
622         {
623             aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
624             aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width();
625             aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height();
626         }
627         else if( aTwoRect.mnSrcWidth+aTwoRect.mnSrcX > aSize.Width() ||
628                  aTwoRect.mnSrcHeight+aTwoRect.mnSrcY > aSize.Height() )
629         {
630             // #i47823# this should not happen at all, but does nonetheless
631             // because BitmapEx allows for mask bitmaps of different size
632             // than image bitmap (broken)
633             if( aTwoRect.mnSrcX >= aSize.Width() ||
634                 aTwoRect.mnSrcY >= aSize.Height() )
635                 return NULL; // this would be a really mad case
636 
637             if( aTwoRect.mnSrcWidth+aTwoRect.mnSrcX > aSize.Width() )
638             {
639                 aTwoRect.mnSrcWidth = aSize.Width()-aTwoRect.mnSrcX;
640                 if( aTwoRect.mnSrcWidth < 1 )
641                 {
642                     aTwoRect.mnSrcX = 0;
643                     aTwoRect.mnSrcWidth = aSize.Width();
644                 }
645             }
646             if( aTwoRect.mnSrcHeight+aTwoRect.mnSrcY > aSize.Height() )
647             {
648                 aTwoRect.mnSrcHeight = aSize.Height() - aTwoRect.mnSrcY;
649                 if( aTwoRect.mnSrcHeight < 1 )
650                 {
651                     aTwoRect.mnSrcY = 0;
652                     aTwoRect.mnSrcHeight = aSize.Height();
653                 }
654             }
655         }
656 
657         XImage* pImage = ImplCreateXImage( GetX11SalData()->GetDisplay(), nScreen,
658                                            nDrawableDepth, aTwoRect );
659 
660         if( pImage )
661         {
662             const_cast<X11SalBitmap*>(this)->mpDDB = new ImplSalDDB( pImage, aDrawable, nScreen, aTwoRect );
663             delete[] pImage->data, pImage->data = NULL;
664             XDestroyImage( pImage );
665 
666             if( mpCache )
667                 mpCache->ImplAdd( const_cast<X11SalBitmap*>(this), mpDDB->ImplGetMemSize() );
668         }
669     }
670 
671     return mpDDB;
672 }
673 
674 // -----------------------------------------------------------------------------
675 
676 void X11SalBitmap::ImplDraw( Drawable           aDrawable,
677                              int                nScreen,
678                              long               nDrawableDepth,
679                              const SalTwoRect&  rTwoRect,
680                              const GC&          rGC ) const
681 {
682     ImplGetDDB( aDrawable, nScreen, nDrawableDepth, rTwoRect );
683     if( mpDDB )
684         mpDDB->ImplDraw( aDrawable, nDrawableDepth, rTwoRect, rGC );
685 }
686 
687 // -----------------------------------------------------------------------------
688 
689 bool X11SalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
690 {
691     Destroy();
692     mpDIB = ImplCreateDIB( rSize, nBitCount, rPal );
693 
694     return( mpDIB != NULL );
695 }
696 
697 // -----------------------------------------------------------------------------
698 
699 bool X11SalBitmap::Create( const SalBitmap& rSSalBmp )
700 {
701     Destroy();
702 
703     const X11SalBitmap& rSalBmp = static_cast<const X11SalBitmap&>( rSSalBmp );
704 
705     if( rSalBmp.mpDIB )
706     {
707         // TODO: reference counting...
708         mpDIB = new BitmapBuffer( *rSalBmp.mpDIB );
709         // TODO: get rid of this when BitmapBuffer gets copy constructor
710         try
711         {
712             mpDIB->mpBits = new sal_uInt8[ mpDIB->mnScanlineSize * mpDIB->mnHeight ];
713         }
714         catch( std::bad_alloc& )
715         {
716             delete mpDIB;
717             mpDIB = NULL;
718         }
719 
720         if( mpDIB )
721             memcpy( mpDIB->mpBits, rSalBmp.mpDIB->mpBits, mpDIB->mnScanlineSize * mpDIB->mnHeight );
722     }
723     else if(  rSalBmp.mpDDB )
724         ImplCreateFromDrawable( rSalBmp.mpDDB->ImplGetPixmap(),
725                                 rSalBmp.mpDDB->ImplGetScreen(),
726                                 rSalBmp.mpDDB->ImplGetDepth(),
727                                 0, 0, rSalBmp.mpDDB->ImplGetWidth(), rSalBmp.mpDDB->ImplGetHeight() );
728 
729     return( ( !rSalBmp.mpDIB && !rSalBmp.mpDDB ) ||
730             ( rSalBmp.mpDIB && ( mpDIB != NULL ) ) ||
731             ( rSalBmp.mpDDB && ( mpDDB != NULL ) ) );
732 }
733 
734 // -----------------------------------------------------------------------------
735 
736 bool X11SalBitmap::Create( const SalBitmap&, SalGraphics* )
737 {
738     return sal_False;
739 }
740 
741 // -----------------------------------------------------------------------------
742 
743 bool X11SalBitmap::Create( const SalBitmap&, sal_uInt16 )
744 {
745     return sal_False;
746 }
747 
748 // -----------------------------------------------------------------------------
749 
750 void X11SalBitmap::Destroy()
751 {
752     if( mpDIB )
753     {
754         delete[] mpDIB->mpBits;
755         delete mpDIB, mpDIB = NULL;
756     }
757 
758     if( mpDDB )
759         delete mpDDB, mpDDB = NULL;
760 
761     if( mpCache )
762         mpCache->ImplRemove( this );
763 }
764 
765 // -----------------------------------------------------------------------------
766 
767 Size X11SalBitmap::GetSize() const
768 {
769     Size aSize;
770 
771     if( mpDIB )
772         aSize.Width() = mpDIB->mnWidth, aSize.Height() = mpDIB->mnHeight;
773     else if( mpDDB )
774         aSize.Width() = mpDDB->ImplGetWidth(), aSize.Height() = mpDDB->ImplGetHeight();
775 
776     return aSize;
777 }
778 
779 // -----------------------------------------------------------------------------
780 
781 sal_uInt16 X11SalBitmap::GetBitCount() const
782 {
783     sal_uInt16 nBitCount;
784 
785     if( mpDIB )
786         nBitCount = mpDIB->mnBitCount;
787     else if( mpDDB )
788         nBitCount = mpDDB->ImplGetDepth();
789     else
790         nBitCount = 0;
791 
792     return nBitCount;
793 }
794 
795 // -----------------------------------------------------------------------------
796 
797 BitmapBuffer* X11SalBitmap::AcquireBuffer( bool )
798 {
799     if( !mpDIB && mpDDB )
800     {
801         mpDIB = ImplCreateDIB( mpDDB->ImplGetPixmap(),
802                                mpDDB->ImplGetScreen(),
803                                mpDDB->ImplGetDepth(),
804                                0, 0, mpDDB->ImplGetWidth(), mpDDB->ImplGetHeight() );
805     }
806 
807     return mpDIB;
808 }
809 
810 // -----------------------------------------------------------------------------
811 
812 void X11SalBitmap::ReleaseBuffer( BitmapBuffer*, bool bReadOnly )
813 {
814     if( !bReadOnly )
815     {
816         if( mpDDB )
817             delete mpDDB, mpDDB = NULL;
818 
819         if( mpCache )
820             mpCache->ImplRemove( this );
821     }
822 }
823 
824 // -----------------------------------------------------------------------------
825 
826 bool X11SalBitmap::GetSystemData( BitmapSystemData& rData )
827 {
828     if( mpDDB )
829     {
830         // Rename/retype pDummy to your likings (though X11 Pixmap is
831         // prolly not a good idea, since it's accessed from
832         // non-platform aware code in vcl/bitmap.hxx)
833         rData.aPixmap = (void*)mpDDB->ImplGetPixmap();
834         rData.mnWidth = mpDDB->ImplGetWidth ();
835         rData.mnHeight = mpDDB->ImplGetHeight ();
836         return true;
837     }
838 
839     return false;
840 }
841 
842 // --------------
843 // - ImplSalDDB -
844 // --------------
845 
846 ImplSalDDB::ImplSalDDB( XImage* pImage, Drawable aDrawable, int nScreen, const SalTwoRect& rTwoRect ) :
847     maPixmap    ( 0 ),
848     maTwoRect   ( rTwoRect ),
849     mnDepth     ( pImage->depth ),
850     mnScreen    ( nScreen )
851 {
852     SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
853     Display*    pXDisp = pSalDisp->GetDisplay();
854 
855     if( (maPixmap = XCreatePixmap( pXDisp, aDrawable, ImplGetWidth(), ImplGetHeight(), ImplGetDepth() )) )
856     {
857         XGCValues   aValues;
858         GC          aGC;
859         int         nValues = GCFunction;
860 
861         aValues.function = GXcopy;
862 
863         if( 1 == mnDepth )
864         {
865             nValues |= ( GCForeground | GCBackground );
866             aValues.foreground = 1, aValues.background = 0;
867         }
868 
869         aGC = XCreateGC( pXDisp, maPixmap, nValues, &aValues );
870         XPutImage( pXDisp, maPixmap, aGC, pImage, 0, 0, 0, 0, maTwoRect.mnDestWidth, maTwoRect.mnDestHeight );
871         XFreeGC( pXDisp, aGC );
872     }
873 }
874 
875 // -----------------------------------------------------------------------------------------
876 // create from XImage
877 
878 ImplSalDDB::ImplSalDDB (Display* pDisplay, XLIB_Window hWindow, int nScreen, XImage* pImage) :
879     mnScreen( nScreen )
880 {
881     maPixmap = XCreatePixmap (pDisplay, hWindow, pImage->width, pImage->height, pImage->depth);
882     if (maPixmap != 0)
883     {
884         XGCValues   aValues;
885         GC          aGC;
886         int         nValues = GCFunction;
887 
888         aValues.function = GXcopy;
889 
890         if (pImage->depth == 1)
891         {
892             nValues |= ( GCForeground | GCBackground );
893             aValues.foreground = 1;
894             aValues.background = 0;
895         }
896 
897         aGC = XCreateGC (pDisplay, maPixmap, nValues, &aValues);
898         XPutImage (pDisplay, maPixmap, aGC, pImage, 0, 0, 0, 0, pImage->width, pImage->height);
899         XFreeGC (pDisplay, aGC);
900 
901         maTwoRect.mnSrcX       = 0;
902         maTwoRect.mnSrcY       = 0;
903         maTwoRect.mnDestX      = 0;
904         maTwoRect.mnDestY      = 0;
905         maTwoRect.mnSrcWidth   = pImage->width;
906         maTwoRect.mnDestWidth  = pImage->width;
907         maTwoRect.mnSrcHeight  = pImage->height;
908         maTwoRect.mnDestHeight = pImage->height;
909 
910         mnDepth = pImage->depth;
911     }
912 }
913 
914 // -----------------------------------------------------------------------------
915 
916 ImplSalDDB::ImplSalDDB( Drawable aDrawable, int nScreen, long nDrawableDepth, long nX, long nY, long nWidth, long nHeight ) :
917     mnDepth( nDrawableDepth ),
918     mnScreen( nScreen )
919 {
920     SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
921     Display*    pXDisp = pSalDisp->GetDisplay();
922 
923     if( (maPixmap = XCreatePixmap( pXDisp, aDrawable, nWidth, nHeight, nDrawableDepth )) )
924     {
925         XGCValues   aValues;
926         GC          aGC;
927         int         nValues = GCFunction;
928 
929         aValues.function = GXcopy;
930 
931         if( 1 == mnDepth )
932         {
933             nValues |= ( GCForeground | GCBackground );
934             aValues.foreground = 1, aValues.background = 0;
935         }
936 
937         aGC = XCreateGC( pXDisp, maPixmap, nValues, &aValues );
938         ImplDraw( aDrawable, nDrawableDepth, maPixmap, mnDepth,
939                   nX, nY, nWidth, nHeight, 0, 0, aGC );
940         XFreeGC( pXDisp, aGC );
941 
942         maTwoRect.mnSrcX = maTwoRect.mnSrcY = maTwoRect.mnDestX = maTwoRect.mnDestY = 0;
943         maTwoRect.mnSrcWidth = maTwoRect.mnDestWidth = nWidth;
944         maTwoRect.mnSrcHeight = maTwoRect.mnDestHeight = nHeight;
945     }
946 }
947 
948 // -----------------------------------------------------------------------------
949 
950 ImplSalDDB::~ImplSalDDB()
951 {
952     if( maPixmap && ImplGetSVData() )
953         XFreePixmap( GetX11SalData()->GetDisplay()->GetDisplay(), maPixmap );
954 }
955 
956 // -----------------------------------------------------------------------------
957 
958 bool ImplSalDDB::ImplMatches( int nScreen, long nDepth, const SalTwoRect& rTwoRect ) const
959 {
960     bool bRet = sal_False;
961 
962     if( ( maPixmap != 0 ) && ( ( mnDepth == nDepth ) || ( 1 == mnDepth ) ) && nScreen == mnScreen)
963     {
964         if( rTwoRect.mnSrcX == maTwoRect.mnSrcX && rTwoRect.mnSrcY == maTwoRect.mnSrcY &&
965             rTwoRect.mnSrcWidth == maTwoRect.mnSrcWidth && rTwoRect.mnSrcHeight == maTwoRect.mnSrcHeight &&
966             rTwoRect.mnDestWidth == maTwoRect.mnDestWidth && rTwoRect.mnDestHeight == maTwoRect.mnDestHeight )
967         {
968             // absolutely indentically
969             bRet = sal_True;
970         }
971         else if( rTwoRect.mnSrcWidth == rTwoRect.mnDestWidth && rTwoRect.mnSrcHeight == rTwoRect.mnDestHeight &&
972                  maTwoRect.mnSrcWidth == maTwoRect.mnDestWidth && maTwoRect.mnSrcHeight == maTwoRect.mnDestHeight &&
973                  rTwoRect.mnSrcX >= maTwoRect.mnSrcX && rTwoRect.mnSrcY >= maTwoRect.mnSrcY &&
974                  ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) <= ( maTwoRect.mnSrcX + maTwoRect.mnSrcWidth ) &&
975                  ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) <= ( maTwoRect.mnSrcY + maTwoRect.mnSrcHeight ) )
976         {
977             bRet = sal_True;
978         }
979     }
980 
981     return bRet;
982 }
983 
984 // -----------------------------------------------------------------------------
985 
986 void ImplSalDDB::ImplDraw( Drawable aDrawable, long nDrawableDepth, const SalTwoRect& rTwoRect, const GC& rGC ) const
987 {
988     ImplDraw( maPixmap, mnDepth, aDrawable, nDrawableDepth,
989               rTwoRect.mnSrcX - maTwoRect.mnSrcX, rTwoRect.mnSrcY - maTwoRect.mnSrcY,
990               rTwoRect.mnDestWidth, rTwoRect.mnDestHeight,
991               rTwoRect.mnDestX, rTwoRect.mnDestY, rGC );
992 }
993 
994 // -----------------------------------------------------------------------------
995 
996 void ImplSalDDB::ImplDraw( Drawable aSrcDrawable, long nSrcDrawableDepth,
997                            Drawable aDstDrawable, long,
998                            long nSrcX, long nSrcY,
999                            long nDestWidth, long nDestHeight,
1000                            long nDestX, long nDestY, const GC& rGC )
1001 {
1002     SalDisplay* pSalDisp = GetX11SalData()->GetDisplay();
1003     Display*    pXDisp = pSalDisp->GetDisplay();
1004 
1005     if( 1 == nSrcDrawableDepth )
1006     {
1007         XCopyPlane( pXDisp, aSrcDrawable, aDstDrawable, rGC,
1008                     nSrcX, nSrcY, nDestWidth, nDestHeight, nDestX, nDestY, 1 );
1009     }
1010     else
1011     {
1012         XCopyArea( pXDisp, aSrcDrawable, aDstDrawable, rGC,
1013                    nSrcX, nSrcY, nDestWidth, nDestHeight, nDestX, nDestY );
1014     }
1015 }
1016 
1017 // ----------------------
1018 // - ImplSalBitmapCache -
1019 // ----------------------
1020 
1021 struct ImplBmpObj
1022 {
1023     X11SalBitmap*   mpBmp;
1024     sal_uLong       mnMemSize;
1025     sal_uLong       mnFlags;
1026 
1027                 ImplBmpObj( X11SalBitmap* pBmp, sal_uLong nMemSize, sal_uLong nFlags ) :
1028                     mpBmp( pBmp ), mnMemSize( nMemSize ), mnFlags( nFlags ) {}
1029 };
1030 
1031 // -----------------------------------------------------------------------------
1032 
1033 ImplSalBitmapCache::ImplSalBitmapCache() :
1034     mnTotalSize( 0UL )
1035 {
1036 }
1037 
1038 // -----------------------------------------------------------------------------
1039 
1040 ImplSalBitmapCache::~ImplSalBitmapCache()
1041 {
1042     ImplClear();
1043 }
1044 
1045 // -----------------------------------------------------------------------------
1046 
1047 void ImplSalBitmapCache::ImplAdd( X11SalBitmap* pBmp, sal_uLong nMemSize, sal_uLong nFlags )
1048 {
1049     ImplBmpObj* pObj;
1050     bool        bFound = sal_False;
1051 
1052     for( pObj = (ImplBmpObj*) maBmpList.Last(); pObj && !bFound; pObj = (ImplBmpObj*) maBmpList.Prev() )
1053         if( pObj->mpBmp == pBmp )
1054             bFound = sal_True;
1055 
1056     mnTotalSize += nMemSize;
1057 
1058     if( bFound )
1059     {
1060         mnTotalSize -= pObj->mnMemSize;
1061         pObj->mnMemSize = nMemSize, pObj->mnFlags = nFlags;
1062     }
1063     else
1064         maBmpList.Insert( new ImplBmpObj( pBmp, nMemSize, nFlags ), LIST_APPEND );
1065 }
1066 
1067 // -----------------------------------------------------------------------------
1068 
1069 void ImplSalBitmapCache::ImplRemove( X11SalBitmap* pBmp )
1070 {
1071     for( ImplBmpObj* pObj = (ImplBmpObj*) maBmpList.Last(); pObj; pObj = (ImplBmpObj*) maBmpList.Prev() )
1072     {
1073         if( pObj->mpBmp == pBmp )
1074         {
1075             maBmpList.Remove( pObj );
1076             pObj->mpBmp->ImplRemovedFromCache();
1077             mnTotalSize -= pObj->mnMemSize;
1078             delete pObj;
1079             break;
1080         }
1081     }
1082 }
1083 
1084 // -----------------------------------------------------------------------------
1085 
1086 void ImplSalBitmapCache::ImplClear()
1087 {
1088     for( ImplBmpObj* pObj = (ImplBmpObj*) maBmpList.First(); pObj; pObj = (ImplBmpObj*) maBmpList.Next() )
1089     {
1090         pObj->mpBmp->ImplRemovedFromCache();
1091         delete pObj;
1092     }
1093 
1094     maBmpList.Clear();
1095     mnTotalSize = 0;
1096 }
1097