xref: /aoo41x/main/vcl/unx/generic/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 <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