| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_vcl.hxx" |
| |
| #include <string.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #ifdef FREEBSD |
| #include <sys/types.h> |
| #endif |
| |
| #include <osl/endian.h> |
| #include <rtl/memory.h> |
| |
| #include <vcl/bitmap.hxx> |
| #include <vcl/salbtype.hxx> |
| |
| #include <tools/prex.h> |
| #include "unx/Xproto.h" |
| #include <tools/postx.h> |
| #include <unx/salunx.h> |
| #include <unx/saldata.hxx> |
| #include <unx/saldisp.hxx> |
| #include <unx/salgdi.h> |
| #include <unx/salbmp.h> |
| #include <unx/salinst.h> |
| |
| // ----------- |
| // - Defines - |
| // ----------- |
| |
| #define SAL_DRAWPIXMAP_MAX_EXT 4096 |
| |
| // ------------- |
| // - SalBitmap - |
| // ------------- |
| |
| SalBitmap* X11SalInstance::CreateSalBitmap() |
| { |
| return new X11SalBitmap(); |
| } |
| |
| ImplSalBitmapCache* X11SalBitmap::mpCache = NULL; |
| sal_uLong X11SalBitmap::mnCacheInstCount = 0; |
| |
| // ----------------------------------------------------------------------------- |
| |
| X11SalBitmap::X11SalBitmap() : |
| mpDIB( NULL ), |
| mpDDB( NULL ) |
| { |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| X11SalBitmap::~X11SalBitmap() |
| { |
| Destroy(); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void X11SalBitmap::ImplCreateCache() |
| { |
| if( !mnCacheInstCount++ ) |
| mpCache = new ImplSalBitmapCache; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void X11SalBitmap::ImplDestroyCache() |
| { |
| DBG_ASSERT( mnCacheInstCount, "X11SalBitmap::ImplDestroyCache(): underflow" ); |
| |
| if( mnCacheInstCount && !--mnCacheInstCount ) |
| delete mpCache, mpCache = NULL; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void X11SalBitmap::ImplRemovedFromCache() |
| { |
| if( mpDDB ) |
| delete mpDDB, mpDDB = NULL; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| BitmapBuffer* X11SalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal ) |
| { |
| DBG_ASSERT( nBitCount == 1 || nBitCount == 4 || nBitCount == 8 || nBitCount == 16 || nBitCount == 24, "Unsupported BitCount!" ); |
| |
| BitmapBuffer* pDIB = NULL; |
| |
| if( rSize.Width() && rSize.Height() ) |
| { |
| try |
| { |
| pDIB = new BitmapBuffer; |
| } |
| catch( std::bad_alloc& ) |
| { |
| pDIB = NULL; |
| } |
| |
| if( pDIB ) |
| { |
| const sal_uInt16 nColors = ( nBitCount <= 8 ) ? ( 1 << nBitCount ) : 0; |
| |
| pDIB->mnFormat = BMP_FORMAT_BOTTOM_UP; |
| |
| switch( nBitCount ) |
| { |
| case( 1 ): pDIB->mnFormat |= BMP_FORMAT_1BIT_MSB_PAL; break; |
| case( 4 ): pDIB->mnFormat |= BMP_FORMAT_4BIT_MSN_PAL; break; |
| case( 8 ): pDIB->mnFormat |= BMP_FORMAT_8BIT_PAL; break; |
| #ifdef OSL_BIGENDIAN |
| case(16 ): |
| pDIB->mnFormat|= BMP_FORMAT_16BIT_TC_MSB_MASK; |
| pDIB->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f ); |
| break; |
| #else |
| case(16 ): |
| pDIB->mnFormat|= BMP_FORMAT_16BIT_TC_LSB_MASK; |
| pDIB->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f ); |
| break; |
| #endif |
| default: |
| nBitCount = 24; |
| //fall through |
| case 24: |
| pDIB->mnFormat |= BMP_FORMAT_24BIT_TC_BGR; |
| break; |
| } |
| |
| pDIB->mnWidth = rSize.Width(); |
| pDIB->mnHeight = rSize.Height(); |
| pDIB->mnScanlineSize = AlignedWidth4Bytes( pDIB->mnWidth * nBitCount ); |
| pDIB->mnBitCount = nBitCount; |
| |
| if( nColors ) |
| { |
| pDIB->maPalette = rPal; |
| pDIB->maPalette.SetEntryCount( nColors ); |
| } |
| |
| try |
| { |
| pDIB->mpBits = new sal_uInt8[ pDIB->mnScanlineSize * pDIB->mnHeight ]; |
| } |
| catch(std::bad_alloc&) |
| { |
| delete pDIB; |
| pDIB = NULL; |
| } |
| } |
| } |
| else |
| pDIB = NULL; |
| |
| return pDIB; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| BitmapBuffer* X11SalBitmap::ImplCreateDIB( Drawable aDrawable, |
| int nScreen, |
| long nDrawableDepth, |
| long nX, long nY, |
| long nWidth, long nHeight ) |
| { |
| BitmapBuffer* pDIB = NULL; |
| |
| if( aDrawable && nWidth && nHeight && nDrawableDepth ) |
| { |
| SalDisplay* pSalDisp = GetX11SalData()->GetDisplay(); |
| SalXLib* pXLib = pSalDisp->GetXLib(); |
| Display* pXDisp = pSalDisp->GetDisplay(); |
| |
| // do not die on XError here |
| // alternatively one could check the coordinates for being offscreen |
| // but this call can actually work on servers with backing store |
| // defaults even if the rectangle is offscreen |
| // so better catch the XError |
| pXLib->PushXErrorLevel( true ); |
| XImage* pImage = XGetImage( pXDisp, aDrawable, nX, nY, nWidth, nHeight, AllPlanes, ZPixmap ); |
| bool bWasError = pXLib->HasXErrorOccured() && pXLib->GetLastXErrorRequestCode() == X_GetImage; |
| pXLib->PopXErrorLevel(); |
| |
| if( ! bWasError && pImage && pImage->data ) |
| { |
| const SalTwoRect aTwoRect = { 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight }; |
| BitmapBuffer aSrcBuf; |
| sal_uLong nDstFormat = BMP_FORMAT_BOTTOM_UP; |
| const BitmapPalette* pDstPal = NULL; |
| |
| aSrcBuf.mnFormat = BMP_FORMAT_TOP_DOWN; |
| aSrcBuf.mnWidth = nWidth; |
| aSrcBuf.mnHeight = nHeight; |
| aSrcBuf.mnBitCount = pImage->bits_per_pixel; |
| aSrcBuf.mnScanlineSize = pImage->bytes_per_line; |
| aSrcBuf.mpBits = (sal_uInt8*) pImage->data; |
| |
| pImage->red_mask = pSalDisp->GetVisual( nScreen ).red_mask; |
| pImage->green_mask = pSalDisp->GetVisual( nScreen ).green_mask; |
| pImage->blue_mask = pSalDisp->GetVisual( nScreen ).blue_mask; |
| |
| switch( aSrcBuf.mnBitCount ) |
| { |
| case( 1 ): |
| { |
| aSrcBuf.mnFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_1BIT_LSB_PAL : BMP_FORMAT_1BIT_MSB_PAL ); |
| nDstFormat |= BMP_FORMAT_1BIT_MSB_PAL; |
| } |
| break; |
| |
| case( 4 ): |
| { |
| aSrcBuf.mnFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_4BIT_LSN_PAL : BMP_FORMAT_4BIT_MSN_PAL ); |
| nDstFormat |= BMP_FORMAT_4BIT_MSN_PAL; |
| } |
| break; |
| |
| case( 8 ): |
| { |
| aSrcBuf.mnFormat |= BMP_FORMAT_8BIT_PAL; |
| nDstFormat |= BMP_FORMAT_8BIT_PAL; |
| } |
| break; |
| |
| case( 16 ): |
| { |
| nDstFormat |= BMP_FORMAT_24BIT_TC_BGR; |
| aSrcBuf.maColorMask = ColorMask( pImage->red_mask, pImage->green_mask, pImage->blue_mask ); |
| |
| if( LSBFirst == pImage->byte_order ) |
| { |
| aSrcBuf.mnFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK; |
| } |
| else |
| { |
| aSrcBuf.mnFormat |= BMP_FORMAT_16BIT_TC_MSB_MASK; |
| // aSrcBuf.maColorMask = ColorMask( pImage->red_mask ), SWAPSHORT( pImage->green_mask ), SWAPSHORT( pImage->blue_mask ) ); |
| } |
| } |
| break; |
| |
| case( 24 ): |
| { |
| if( ( LSBFirst == pImage->byte_order ) && ( pImage->red_mask == 0xFF ) ) |
| aSrcBuf.mnFormat |= BMP_FORMAT_24BIT_TC_RGB; |
| else |
| aSrcBuf.mnFormat |= BMP_FORMAT_24BIT_TC_BGR; |
| |
| nDstFormat |= BMP_FORMAT_24BIT_TC_BGR; |
| } |
| break; |
| |
| case( 32 ): |
| { |
| if( LSBFirst == pImage->byte_order ) |
| aSrcBuf.mnFormat |= ( pSalDisp->GetVisual(nScreen).red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_RGBA : BMP_FORMAT_32BIT_TC_BGRA ); |
| else |
| aSrcBuf.mnFormat |= ( pSalDisp->GetVisual(nScreen).red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_ABGR : BMP_FORMAT_32BIT_TC_ARGB ); |
| |
| nDstFormat |= BMP_FORMAT_24BIT_TC_BGR; |
| } |
| break; |
| } |
| |
| BitmapPalette& rPal = aSrcBuf.maPalette; |
| |
| if( aSrcBuf.mnBitCount == 1 ) |
| { |
| rPal.SetEntryCount( 2 ); |
| pDstPal = &rPal; |
| |
| rPal[ 0 ] = Color( COL_BLACK ); |
| rPal[ 1 ] = Color( COL_WHITE ); |
| } |
| else if( aSrcBuf.mnBitCount <= 8 ) |
| { |
| const SalColormap& rColMap = pSalDisp->GetColormap( nScreen ); |
| const sal_uInt16 nCols = Min( (sal_uLong)rColMap.GetUsed(), (sal_uLong)(1 << nDrawableDepth) ); |
| |
| rPal.SetEntryCount( nCols ); |
| pDstPal = &rPal; |
| |
| for( sal_uInt16 i = 0; i < nCols; i++ ) |
| { |
| const SalColor nColor( rColMap.GetColor( i ) ); |
| BitmapColor& rBmpCol = rPal[ i ]; |
| |
| rBmpCol.SetRed( SALCOLOR_RED( nColor ) ); |
| rBmpCol.SetGreen( SALCOLOR_GREEN( nColor ) ); |
| rBmpCol.SetBlue( SALCOLOR_BLUE( nColor ) ); |
| } |
| } |
| |
| nDstFormat = aSrcBuf.mnFormat; |
| pDIB = StretchAndConvert( aSrcBuf, aTwoRect, nDstFormat, |
| const_cast<BitmapPalette*>(pDstPal), &aSrcBuf.maColorMask ); |
| XDestroyImage( pImage ); |
| } |
| } |
| |
| return pDIB; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| XImage* X11SalBitmap::ImplCreateXImage( SalDisplay *pSalDisp, int nScreen, long nDepth, const SalTwoRect& rTwoRect ) const |
| { |
| XImage* pImage = NULL; |
| |
| if( !mpDIB && mpDDB ) |
| { |
| const_cast<X11SalBitmap*>(this)->mpDIB = |
| ImplCreateDIB( mpDDB->ImplGetPixmap(), |
| mpDDB->ImplGetScreen(), |
| mpDDB->ImplGetDepth(), |
| 0, 0, |
| mpDDB->ImplGetWidth(), |
| mpDDB->ImplGetHeight() ); |
| } |
| |
| if( mpDIB && mpDIB->mnWidth && mpDIB->mnHeight ) |
| { |
| Display* pXDisp = pSalDisp->GetDisplay(); |
| long nWidth = rTwoRect.mnDestWidth; |
| long nHeight = rTwoRect.mnDestHeight; |
| |
| if( 1 == GetBitCount() ) |
| nDepth = 1; |
| |
| pImage = XCreateImage( pXDisp, pSalDisp->GetVisual( nScreen ).GetVisual(), |
| nDepth, ( 1 == nDepth ) ? XYBitmap :ZPixmap, 0, NULL, |
| nWidth, nHeight, 32, 0 ); |
| |
| if( pImage ) |
| { |
| BitmapBuffer* pDstBuf; |
| sal_uLong nDstFormat = BMP_FORMAT_TOP_DOWN; |
| BitmapPalette* pPal = NULL; |
| ColorMask* pMask = NULL; |
| |
| switch( pImage->bits_per_pixel ) |
| { |
| case( 1 ): |
| nDstFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_1BIT_LSB_PAL : BMP_FORMAT_1BIT_MSB_PAL ); |
| break; |
| |
| case( 4 ): |
| nDstFormat |= ( LSBFirst == pImage->bitmap_bit_order ? BMP_FORMAT_4BIT_LSN_PAL : BMP_FORMAT_4BIT_MSN_PAL ); |
| break; |
| |
| case( 8 ): |
| nDstFormat |= BMP_FORMAT_8BIT_PAL; |
| break; |
| |
| case( 16 ): |
| { |
| #ifdef OSL_BIGENDIAN |
| |
| if( MSBFirst == pImage->byte_order ) |
| nDstFormat |= BMP_FORMAT_16BIT_TC_MSB_MASK; |
| else |
| nDstFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK; |
| |
| #else /* OSL_LITENDIAN */ |
| |
| nDstFormat |= BMP_FORMAT_16BIT_TC_LSB_MASK; |
| if( MSBFirst == pImage->byte_order ) |
| pImage->byte_order = LSBFirst; |
| |
| #endif |
| |
| pMask = new ColorMask( pImage->red_mask, pImage->green_mask, pImage->blue_mask ); |
| } |
| break; |
| |
| case( 24 ): |
| { |
| if( ( LSBFirst == pImage->byte_order ) && ( pImage->red_mask == 0xFF ) ) |
| nDstFormat |= BMP_FORMAT_24BIT_TC_RGB; |
| else |
| nDstFormat |= BMP_FORMAT_24BIT_TC_BGR; |
| } |
| break; |
| |
| case( 32 ): |
| { |
| if( LSBFirst == pImage->byte_order ) |
| nDstFormat |= ( pImage->red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_RGBA : BMP_FORMAT_32BIT_TC_BGRA ); |
| else |
| nDstFormat |= ( pImage->red_mask == 0xFF ? BMP_FORMAT_32BIT_TC_ABGR : BMP_FORMAT_32BIT_TC_ARGB ); |
| } |
| break; |
| } |
| |
| if( pImage->depth == 1 ) |
| { |
| pPal = new BitmapPalette( 2 ); |
| (*pPal)[ 0 ] = Color( COL_BLACK ); |
| (*pPal)[ 1 ] = Color( COL_WHITE ); |
| } |
| else if( pImage->depth <= 8 ) |
| { |
| const SalColormap& rColMap = pSalDisp->GetColormap( nScreen ); |
| const sal_uInt16 nCols = Min( (sal_uLong)rColMap.GetUsed(), (sal_uLong)(1 << pImage->depth) ); |
| |
| pPal = new BitmapPalette( nCols ); |
| |
| for( sal_uInt16 i = 0; i < nCols; i++ ) |
| { |
| const SalColor nColor( rColMap.GetColor( i ) ); |
| BitmapColor& rBmpCol = (*pPal)[ i ]; |
| |
| rBmpCol.SetRed( SALCOLOR_RED( nColor ) ); |
| rBmpCol.SetGreen( SALCOLOR_GREEN( nColor ) ); |
| rBmpCol.SetBlue( SALCOLOR_BLUE( nColor ) ); |
| } |
| } |
| |
| pDstBuf = StretchAndConvert( *mpDIB, rTwoRect, nDstFormat, pPal, pMask ); |
| delete pPal; |
| delete pMask; |
| |
| if( pDstBuf && pDstBuf->mpBits ) |
| { |
| // set data in buffer as data member in pImage |
| pImage->data = (char*) pDstBuf->mpBits; |
| |
| // destroy buffer; don't destroy allocated data in buffer |
| delete pDstBuf; |
| } |
| else |
| { |
| XDestroyImage( pImage ); |
| pImage = NULL; |
| } |
| } |
| } |
| |
| return pImage; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| bool X11SalBitmap::ImplCreateFromDrawable( Drawable aDrawable, |
| int nScreen, long nDrawableDepth, |
| long nX, long nY, long nWidth, long nHeight ) |
| { |
| Destroy(); |
| |
| if( aDrawable && nWidth && nHeight && nDrawableDepth ) |
| mpDDB = new ImplSalDDB( aDrawable, nScreen, nDrawableDepth, nX, nY, nWidth, nHeight ); |
| |
| return( mpDDB != NULL ); |
| } |
| // ----------------------------------------------------------------------------- |
| |
| bool |
| X11SalBitmap::SnapShot (Display* pDisplay, XLIB_Window hWindow) |
| { |
| if (hWindow != None) |
| { |
| XWindowAttributes aAttribute; |
| XGetWindowAttributes (pDisplay, hWindow, &aAttribute); |
| if (aAttribute.map_state == IsViewable) |
| { |
| // get coordinates relative to root window |
| XLIB_Window hPetitFleur; |
| int nRootX, nRootY; |
| |
| if (XTranslateCoordinates (pDisplay, hWindow, aAttribute.root, |
| 0, 0, &nRootX, &nRootY, &hPetitFleur)) |
| { |
| XWindowAttributes aRootAttribute; |
| XGetWindowAttributes (pDisplay, aAttribute.root, &aRootAttribute); |
| |
| int width = aAttribute.width; |
| int height = aAttribute.height; |
| int x = nRootX; |
| int y = nRootY; |
| |
| // horizontal range check |
| if (x < 0) |
| { |
| width = width + x; |
| x = 0; |
| } |
| else |
| if (x > aRootAttribute.width) |
| { |
| width = 0; |
| x = aRootAttribute.width; |
| } |
| else |
| if (x + width > aRootAttribute.width) |
| { |
| width = aRootAttribute.width - x; |
| } |
| |
| // vertical range check |
| if (y < 0) |
| { |
| height = height + y; |
| y = 0; |
| } |
| else |
| if (y > aRootAttribute.height) |
| { |
| height = 0; |
| y = aRootAttribute.height; |
| } |
| else |
| if (y + height > aRootAttribute.height) |
| { |
| height = aRootAttribute.height - y; |
| } |
| |
| if ((width > 0) && (height > 0)) |
| { |
| XImage* pImage = XGetImage( pDisplay, aAttribute.root, |
| x, y, width, height, AllPlanes, ZPixmap ); |
| bool bSnapShot = ImplCreateFromXImage( pDisplay, |
| aAttribute.root, |
| XScreenNumberOfScreen( aAttribute.screen ), |
| pImage ); |
| XDestroyImage (pImage); |
| |
| return bSnapShot; |
| } |
| } |
| } |
| } |
| |
| return False; |
| } |
| |
| bool |
| X11SalBitmap::ImplCreateFromXImage (Display* pDisplay, XLIB_Window hWindow, int nScreen, XImage* pImage) |
| { |
| Destroy(); |
| |
| if (pImage != NULL && pImage->width != 0 && pImage->height != 0 && pImage->depth != 0) |
| { |
| mpDDB = new ImplSalDDB (pDisplay, hWindow, nScreen, pImage); |
| return True; |
| } |
| return False; |
| } |
| |
| ImplSalDDB* X11SalBitmap::ImplGetDDB( Drawable aDrawable, |
| int nScreen, |
| long nDrawableDepth, |
| const SalTwoRect& rTwoRect ) const |
| { |
| if( !mpDDB || !mpDDB->ImplMatches( nScreen, nDrawableDepth, rTwoRect ) ) |
| { |
| if( mpDDB ) |
| { |
| // do we already have a DIB? if not, create aDIB from current DDB first |
| if( !mpDIB ) |
| { |
| const_cast<X11SalBitmap*>(this)->mpDIB = ImplCreateDIB( mpDDB->ImplGetPixmap(), |
| mpDDB->ImplGetScreen(), |
| mpDDB->ImplGetDepth(), |
| 0, 0, |
| mpDDB->ImplGetWidth(), |
| mpDDB->ImplGetHeight() ); |
| } |
| |
| delete mpDDB, const_cast<X11SalBitmap*>(this)->mpDDB = NULL; |
| } |
| |
| if( mpCache ) |
| mpCache->ImplRemove( const_cast<X11SalBitmap*>(this) ); |
| |
| SalTwoRect aTwoRect( rTwoRect ); |
| if( aTwoRect.mnSrcX < 0 ) |
| { |
| aTwoRect.mnSrcWidth += aTwoRect.mnSrcX; |
| aTwoRect.mnSrcX = 0; |
| } |
| if( aTwoRect.mnSrcY < 0 ) |
| { |
| aTwoRect.mnSrcHeight += aTwoRect.mnSrcY; |
| aTwoRect.mnSrcY = 0; |
| } |
| |
| // create new DDB from DIB |
| const Size aSize( GetSize() ); |
| if( aTwoRect.mnSrcWidth == aTwoRect.mnDestWidth && |
| aTwoRect.mnSrcHeight == aTwoRect.mnDestHeight ) |
| { |
| aTwoRect.mnSrcX = aTwoRect.mnSrcY = aTwoRect.mnDestX = aTwoRect.mnDestY = 0; |
| aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = aSize.Width(); |
| aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = aSize.Height(); |
| } |
| else if( aTwoRect.mnSrcWidth+aTwoRect.mnSrcX > aSize.Width() || |
| aTwoRect.mnSrcHeight+aTwoRect.mnSrcY > aSize.Height() ) |
| { |
| // #i47823# this should not happen at all, but does nonetheless |
| // because BitmapEx allows for mask bitmaps of different size |
| // than image bitmap (broken) |
| if( aTwoRect.mnSrcX >= aSize.Width() || |
| aTwoRect.mnSrcY >= aSize.Height() ) |
| return NULL; // this would be a really mad case |
| |
| if( aTwoRect.mnSrcWidth+aTwoRect.mnSrcX > aSize.Width() ) |
| { |
| aTwoRect.mnSrcWidth = aSize.Width()-aTwoRect.mnSrcX; |
| if( aTwoRect.mnSrcWidth < 1 ) |
| { |
| aTwoRect.mnSrcX = 0; |
| aTwoRect.mnSrcWidth = aSize.Width(); |
| } |
| } |
| if( aTwoRect.mnSrcHeight+aTwoRect.mnSrcY > aSize.Height() ) |
| { |
| aTwoRect.mnSrcHeight = aSize.Height() - aTwoRect.mnSrcY; |
| if( aTwoRect.mnSrcHeight < 1 ) |
| { |
| aTwoRect.mnSrcY = 0; |
| aTwoRect.mnSrcHeight = aSize.Height(); |
| } |
| } |
| } |
| |
| XImage* pImage = ImplCreateXImage( GetX11SalData()->GetDisplay(), nScreen, |
| nDrawableDepth, aTwoRect ); |
| |
| if( pImage ) |
| { |
| const_cast<X11SalBitmap*>(this)->mpDDB = new ImplSalDDB( pImage, aDrawable, nScreen, aTwoRect ); |
| delete[] pImage->data, pImage->data = NULL; |
| XDestroyImage( pImage ); |
| |
| if( mpCache ) |
| mpCache->ImplAdd( const_cast<X11SalBitmap*>(this), mpDDB->ImplGetMemSize() ); |
| } |
| } |
| |
| return mpDDB; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void X11SalBitmap::ImplDraw( Drawable aDrawable, |
| int nScreen, |
| long nDrawableDepth, |
| const SalTwoRect& rTwoRect, |
| const GC& rGC ) const |
| { |
| ImplGetDDB( aDrawable, nScreen, nDrawableDepth, rTwoRect ); |
| if( mpDDB ) |
| mpDDB->ImplDraw( aDrawable, nDrawableDepth, rTwoRect, rGC ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| bool X11SalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal ) |
| { |
| Destroy(); |
| mpDIB = ImplCreateDIB( rSize, nBitCount, rPal ); |
| |
| return( mpDIB != NULL ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| bool X11SalBitmap::Create( const SalBitmap& rSSalBmp ) |
| { |
| Destroy(); |
| |
| const X11SalBitmap& rSalBmp = static_cast<const X11SalBitmap&>( rSSalBmp ); |
| |
| if( rSalBmp.mpDIB ) |
| { |
| // TODO: reference counting... |
| mpDIB = new BitmapBuffer( *rSalBmp.mpDIB ); |
| // TODO: get rid of this when BitmapBuffer gets copy constructor |
| try |
| { |
| mpDIB->mpBits = new sal_uInt8[ mpDIB->mnScanlineSize * mpDIB->mnHeight ]; |
| } |
| catch( std::bad_alloc& ) |
| { |
| delete mpDIB; |
| mpDIB = NULL; |
| } |
| |
| if( mpDIB ) |
| memcpy( mpDIB->mpBits, rSalBmp.mpDIB->mpBits, mpDIB->mnScanlineSize * mpDIB->mnHeight ); |
| } |
| else if( rSalBmp.mpDDB ) |
| ImplCreateFromDrawable( rSalBmp.mpDDB->ImplGetPixmap(), |
| rSalBmp.mpDDB->ImplGetScreen(), |
| rSalBmp.mpDDB->ImplGetDepth(), |
| 0, 0, rSalBmp.mpDDB->ImplGetWidth(), rSalBmp.mpDDB->ImplGetHeight() ); |
| |
| return( ( !rSalBmp.mpDIB && !rSalBmp.mpDDB ) || |
| ( rSalBmp.mpDIB && ( mpDIB != NULL ) ) || |
| ( rSalBmp.mpDDB && ( mpDDB != NULL ) ) ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| bool X11SalBitmap::Create( const SalBitmap&, SalGraphics* ) |
| { |
| return sal_False; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| bool X11SalBitmap::Create( const SalBitmap&, sal_uInt16 ) |
| { |
| return sal_False; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void X11SalBitmap::Destroy() |
| { |
| if( mpDIB ) |
| { |
| delete[] mpDIB->mpBits; |
| delete mpDIB, mpDIB = NULL; |
| } |
| |
| if( mpDDB ) |
| delete mpDDB, mpDDB = NULL; |
| |
| if( mpCache ) |
| mpCache->ImplRemove( this ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| Size X11SalBitmap::GetSize() const |
| { |
| Size aSize; |
| |
| if( mpDIB ) |
| aSize.Width() = mpDIB->mnWidth, aSize.Height() = mpDIB->mnHeight; |
| else if( mpDDB ) |
| aSize.Width() = mpDDB->ImplGetWidth(), aSize.Height() = mpDDB->ImplGetHeight(); |
| |
| return aSize; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_uInt16 X11SalBitmap::GetBitCount() const |
| { |
| sal_uInt16 nBitCount; |
| |
| if( mpDIB ) |
| nBitCount = mpDIB->mnBitCount; |
| else if( mpDDB ) |
| nBitCount = mpDDB->ImplGetDepth(); |
| else |
| nBitCount = 0; |
| |
| return nBitCount; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| BitmapBuffer* X11SalBitmap::AcquireBuffer( bool ) |
| { |
| if( !mpDIB && mpDDB ) |
| { |
| mpDIB = ImplCreateDIB( mpDDB->ImplGetPixmap(), |
| mpDDB->ImplGetScreen(), |
| mpDDB->ImplGetDepth(), |
| 0, 0, mpDDB->ImplGetWidth(), mpDDB->ImplGetHeight() ); |
| } |
| |
| return mpDIB; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void X11SalBitmap::ReleaseBuffer( BitmapBuffer*, bool bReadOnly ) |
| { |
| if( !bReadOnly ) |
| { |
| if( mpDDB ) |
| delete mpDDB, mpDDB = NULL; |
| |
| if( mpCache ) |
| mpCache->ImplRemove( this ); |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| bool X11SalBitmap::GetSystemData( BitmapSystemData& rData ) |
| { |
| if( mpDDB ) |
| { |
| // Rename/retype pDummy to your likings (though X11 Pixmap is |
| // prolly not a good idea, since it's accessed from |
| // non-platform aware code in vcl/bitmap.hxx) |
| rData.aPixmap = (void*)mpDDB->ImplGetPixmap(); |
| rData.mnWidth = mpDDB->ImplGetWidth (); |
| rData.mnHeight = mpDDB->ImplGetHeight (); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| // -------------- |
| // - ImplSalDDB - |
| // -------------- |
| |
| ImplSalDDB::ImplSalDDB( XImage* pImage, Drawable aDrawable, int nScreen, const SalTwoRect& rTwoRect ) : |
| maPixmap ( 0 ), |
| maTwoRect ( rTwoRect ), |
| mnDepth ( pImage->depth ), |
| mnScreen ( nScreen ) |
| { |
| SalDisplay* pSalDisp = GetX11SalData()->GetDisplay(); |
| Display* pXDisp = pSalDisp->GetDisplay(); |
| |
| if( (maPixmap = XCreatePixmap( pXDisp, aDrawable, ImplGetWidth(), ImplGetHeight(), ImplGetDepth() )) ) |
| { |
| XGCValues aValues; |
| GC aGC; |
| int nValues = GCFunction; |
| |
| aValues.function = GXcopy; |
| |
| if( 1 == mnDepth ) |
| { |
| nValues |= ( GCForeground | GCBackground ); |
| aValues.foreground = 1, aValues.background = 0; |
| } |
| |
| aGC = XCreateGC( pXDisp, maPixmap, nValues, &aValues ); |
| XPutImage( pXDisp, maPixmap, aGC, pImage, 0, 0, 0, 0, maTwoRect.mnDestWidth, maTwoRect.mnDestHeight ); |
| XFreeGC( pXDisp, aGC ); |
| } |
| } |
| |
| // ----------------------------------------------------------------------------------------- |
| // create from XImage |
| |
| ImplSalDDB::ImplSalDDB (Display* pDisplay, XLIB_Window hWindow, int nScreen, XImage* pImage) : |
| mnScreen( nScreen ) |
| { |
| maPixmap = XCreatePixmap (pDisplay, hWindow, pImage->width, pImage->height, pImage->depth); |
| if (maPixmap != 0) |
| { |
| XGCValues aValues; |
| GC aGC; |
| int nValues = GCFunction; |
| |
| aValues.function = GXcopy; |
| |
| if (pImage->depth == 1) |
| { |
| nValues |= ( GCForeground | GCBackground ); |
| aValues.foreground = 1; |
| aValues.background = 0; |
| } |
| |
| aGC = XCreateGC (pDisplay, maPixmap, nValues, &aValues); |
| XPutImage (pDisplay, maPixmap, aGC, pImage, 0, 0, 0, 0, pImage->width, pImage->height); |
| XFreeGC (pDisplay, aGC); |
| |
| maTwoRect.mnSrcX = 0; |
| maTwoRect.mnSrcY = 0; |
| maTwoRect.mnDestX = 0; |
| maTwoRect.mnDestY = 0; |
| maTwoRect.mnSrcWidth = pImage->width; |
| maTwoRect.mnDestWidth = pImage->width; |
| maTwoRect.mnSrcHeight = pImage->height; |
| maTwoRect.mnDestHeight = pImage->height; |
| |
| mnDepth = pImage->depth; |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| ImplSalDDB::ImplSalDDB( Drawable aDrawable, int nScreen, long nDrawableDepth, long nX, long nY, long nWidth, long nHeight ) : |
| mnDepth( nDrawableDepth ), |
| mnScreen( nScreen ) |
| { |
| SalDisplay* pSalDisp = GetX11SalData()->GetDisplay(); |
| Display* pXDisp = pSalDisp->GetDisplay(); |
| |
| if( (maPixmap = XCreatePixmap( pXDisp, aDrawable, nWidth, nHeight, nDrawableDepth )) ) |
| { |
| XGCValues aValues; |
| GC aGC; |
| int nValues = GCFunction; |
| |
| aValues.function = GXcopy; |
| |
| if( 1 == mnDepth ) |
| { |
| nValues |= ( GCForeground | GCBackground ); |
| aValues.foreground = 1, aValues.background = 0; |
| } |
| |
| aGC = XCreateGC( pXDisp, maPixmap, nValues, &aValues ); |
| ImplDraw( aDrawable, nDrawableDepth, maPixmap, mnDepth, |
| nX, nY, nWidth, nHeight, 0, 0, aGC ); |
| XFreeGC( pXDisp, aGC ); |
| |
| maTwoRect.mnSrcX = maTwoRect.mnSrcY = maTwoRect.mnDestX = maTwoRect.mnDestY = 0; |
| maTwoRect.mnSrcWidth = maTwoRect.mnDestWidth = nWidth; |
| maTwoRect.mnSrcHeight = maTwoRect.mnDestHeight = nHeight; |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| ImplSalDDB::~ImplSalDDB() |
| { |
| if( maPixmap && ImplGetSVData() ) |
| XFreePixmap( GetX11SalData()->GetDisplay()->GetDisplay(), maPixmap ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| bool ImplSalDDB::ImplMatches( int nScreen, long nDepth, const SalTwoRect& rTwoRect ) const |
| { |
| bool bRet = sal_False; |
| |
| if( ( maPixmap != 0 ) && ( ( mnDepth == nDepth ) || ( 1 == mnDepth ) ) && nScreen == mnScreen) |
| { |
| if( rTwoRect.mnSrcX == maTwoRect.mnSrcX && rTwoRect.mnSrcY == maTwoRect.mnSrcY && |
| rTwoRect.mnSrcWidth == maTwoRect.mnSrcWidth && rTwoRect.mnSrcHeight == maTwoRect.mnSrcHeight && |
| rTwoRect.mnDestWidth == maTwoRect.mnDestWidth && rTwoRect.mnDestHeight == maTwoRect.mnDestHeight ) |
| { |
| // absolutely indentically |
| bRet = sal_True; |
| } |
| else if( rTwoRect.mnSrcWidth == rTwoRect.mnDestWidth && rTwoRect.mnSrcHeight == rTwoRect.mnDestHeight && |
| maTwoRect.mnSrcWidth == maTwoRect.mnDestWidth && maTwoRect.mnSrcHeight == maTwoRect.mnDestHeight && |
| rTwoRect.mnSrcX >= maTwoRect.mnSrcX && rTwoRect.mnSrcY >= maTwoRect.mnSrcY && |
| ( rTwoRect.mnSrcX + rTwoRect.mnSrcWidth ) <= ( maTwoRect.mnSrcX + maTwoRect.mnSrcWidth ) && |
| ( rTwoRect.mnSrcY + rTwoRect.mnSrcHeight ) <= ( maTwoRect.mnSrcY + maTwoRect.mnSrcHeight ) ) |
| { |
| bRet = sal_True; |
| } |
| } |
| |
| return bRet; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void ImplSalDDB::ImplDraw( Drawable aDrawable, long nDrawableDepth, const SalTwoRect& rTwoRect, const GC& rGC ) const |
| { |
| ImplDraw( maPixmap, mnDepth, aDrawable, nDrawableDepth, |
| rTwoRect.mnSrcX - maTwoRect.mnSrcX, rTwoRect.mnSrcY - maTwoRect.mnSrcY, |
| rTwoRect.mnDestWidth, rTwoRect.mnDestHeight, |
| rTwoRect.mnDestX, rTwoRect.mnDestY, rGC ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void ImplSalDDB::ImplDraw( Drawable aSrcDrawable, long nSrcDrawableDepth, |
| Drawable aDstDrawable, long, |
| long nSrcX, long nSrcY, |
| long nDestWidth, long nDestHeight, |
| long nDestX, long nDestY, const GC& rGC ) |
| { |
| SalDisplay* pSalDisp = GetX11SalData()->GetDisplay(); |
| Display* pXDisp = pSalDisp->GetDisplay(); |
| |
| if( 1 == nSrcDrawableDepth ) |
| { |
| XCopyPlane( pXDisp, aSrcDrawable, aDstDrawable, rGC, |
| nSrcX, nSrcY, nDestWidth, nDestHeight, nDestX, nDestY, 1 ); |
| } |
| else |
| { |
| XCopyArea( pXDisp, aSrcDrawable, aDstDrawable, rGC, |
| nSrcX, nSrcY, nDestWidth, nDestHeight, nDestX, nDestY ); |
| } |
| } |
| |
| // ---------------------- |
| // - ImplSalBitmapCache - |
| // ---------------------- |
| |
| struct ImplBmpObj |
| { |
| X11SalBitmap* mpBmp; |
| sal_uLong mnMemSize; |
| sal_uLong mnFlags; |
| |
| ImplBmpObj( X11SalBitmap* pBmp, sal_uLong nMemSize, sal_uLong nFlags ) : |
| mpBmp( pBmp ), mnMemSize( nMemSize ), mnFlags( nFlags ) {} |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| |
| ImplSalBitmapCache::ImplSalBitmapCache() : |
| mnTotalSize( 0UL ) |
| { |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| ImplSalBitmapCache::~ImplSalBitmapCache() |
| { |
| ImplClear(); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void ImplSalBitmapCache::ImplAdd( X11SalBitmap* pBmp, sal_uLong nMemSize, sal_uLong nFlags ) |
| { |
| ImplBmpObj* pObj; |
| bool bFound = sal_False; |
| |
| for( pObj = (ImplBmpObj*) maBmpList.Last(); pObj && !bFound; pObj = (ImplBmpObj*) maBmpList.Prev() ) |
| if( pObj->mpBmp == pBmp ) |
| bFound = sal_True; |
| |
| mnTotalSize += nMemSize; |
| |
| if( bFound ) |
| { |
| mnTotalSize -= pObj->mnMemSize; |
| pObj->mnMemSize = nMemSize, pObj->mnFlags = nFlags; |
| } |
| else |
| maBmpList.Insert( new ImplBmpObj( pBmp, nMemSize, nFlags ), LIST_APPEND ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void ImplSalBitmapCache::ImplRemove( X11SalBitmap* pBmp ) |
| { |
| for( ImplBmpObj* pObj = (ImplBmpObj*) maBmpList.Last(); pObj; pObj = (ImplBmpObj*) maBmpList.Prev() ) |
| { |
| if( pObj->mpBmp == pBmp ) |
| { |
| maBmpList.Remove( pObj ); |
| pObj->mpBmp->ImplRemovedFromCache(); |
| mnTotalSize -= pObj->mnMemSize; |
| delete pObj; |
| break; |
| } |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void ImplSalBitmapCache::ImplClear() |
| { |
| for( ImplBmpObj* pObj = (ImplBmpObj*) maBmpList.First(); pObj; pObj = (ImplBmpObj*) maBmpList.Next() ) |
| { |
| pObj->mpBmp->ImplRemovedFromCache(); |
| delete pObj; |
| } |
| |
| maBmpList.Clear(); |
| mnTotalSize = 0; |
| } |