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