/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #ifdef FREEBSD #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined HAVE_VALGRIND_HEADERS #include #endif #include ImplSalBitmapCache* X11SalBitmap::mpCache = nullptr; unsigned int X11SalBitmap::mnCacheInstCount = 0; X11SalBitmap::X11SalBitmap() : mbGrey( false ) { } X11SalBitmap::~X11SalBitmap() { Destroy(); } void X11SalBitmap::ImplCreateCache() { if( !mnCacheInstCount++ ) mpCache = new ImplSalBitmapCache; } void X11SalBitmap::ImplDestroyCache() { SAL_WARN_IF( !mnCacheInstCount, "vcl", "X11SalBitmap::ImplDestroyCache(): underflow" ); if( mnCacheInstCount && !--mnCacheInstCount ) { delete mpCache; mpCache = nullptr; } } void X11SalBitmap::ImplRemovedFromCache() { mpDDB.reset(); } #if defined HAVE_VALGRIND_HEADERS namespace { void blankExtraSpace(BitmapBuffer* pDIB) { size_t nExtraSpaceInScanLine = pDIB->mnScanlineSize - pDIB->mnWidth * pDIB->mnBitCount / 8; if (nExtraSpaceInScanLine) { for (tools::Long i = 0; i < pDIB->mnHeight; ++i) { sal_uInt8 *pRow = pDIB->mpBits + (i * pDIB->mnScanlineSize); memset(pRow + (pDIB->mnScanlineSize - nExtraSpaceInScanLine), 0, nExtraSpaceInScanLine); } } } } #endif std::unique_ptr X11SalBitmap::ImplCreateDIB( const Size& rSize, vcl::PixelFormat ePixelFormat, const BitmapPalette& rPal) { std::unique_ptr pDIB; if( !rSize.Width() || !rSize.Height() ) return nullptr; try { pDIB.reset(new BitmapBuffer); } catch (const std::bad_alloc&) { return nullptr; } pDIB->mnFormat = ScanlineFormat::NONE; switch(ePixelFormat) { case vcl::PixelFormat::N1_BPP: pDIB->mnFormat |= ScanlineFormat::N1BitMsbPal; break; case vcl::PixelFormat::N8_BPP: pDIB->mnFormat |= ScanlineFormat::N8BitPal; break; case vcl::PixelFormat::N24_BPP: pDIB->mnFormat |= ScanlineFormat::N24BitTcBgr; break; case vcl::PixelFormat::N32_BPP: default: SAL_WARN("vcl.gdi", "32-bit images not supported, converting to 24-bit"); ePixelFormat = vcl::PixelFormat::N24_BPP; pDIB->mnFormat |= ScanlineFormat::N24BitTcBgr; break; } sal_uInt16 nColors = 0; if (ePixelFormat <= vcl::PixelFormat::N8_BPP) nColors = vcl::numberOfColors(ePixelFormat); pDIB->mnWidth = rSize.Width(); pDIB->mnHeight = rSize.Height(); tools::Long nScanlineBase; bool bFail = o3tl::checked_multiply(pDIB->mnWidth, vcl::pixelFormatBitCount(ePixelFormat), nScanlineBase); if (bFail) { SAL_WARN("vcl.gdi", "checked multiply failed"); return nullptr; } pDIB->mnScanlineSize = AlignedWidth4Bytes(nScanlineBase); if (pDIB->mnScanlineSize < nScanlineBase/8) { SAL_WARN("vcl.gdi", "scanline calculation wraparound"); return nullptr; } pDIB->mnBitCount = vcl::pixelFormatBitCount(ePixelFormat); if( nColors ) { pDIB->maPalette = rPal; pDIB->maPalette.SetEntryCount( nColors ); } try { pDIB->mpBits = new sal_uInt8[ pDIB->mnScanlineSize * pDIB->mnHeight ]; #if defined HAVE_VALGRIND_HEADERS if (RUNNING_ON_VALGRIND) blankExtraSpace(pDIB.get()); #endif } catch (const std::bad_alloc&) { return nullptr; } return pDIB; } std::unique_ptr X11SalBitmap::ImplCreateDIB( Drawable aDrawable, SalX11Screen nScreen, tools::Long nDrawableDepth, tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, bool bGrey ) { std::unique_ptr pDIB; if( aDrawable && nWidth && nHeight && nDrawableDepth ) { SalDisplay* pSalDisp = vcl_sal::getSalDisplay(GetGenericUnixSalData()); 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 GetGenericUnixSalData()->ErrorTrapPush(); XImage* pImage = XGetImage( pXDisp, aDrawable, nX, nY, nWidth, nHeight, AllPlanes, ZPixmap ); bool bWasError = GetGenericUnixSalData()->ErrorTrapPop( false ); if( ! bWasError && pImage && pImage->data ) { const SalTwoRect aTwoRect = { 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight }; BitmapBuffer aSrcBuf; std::optional pDstPal; aSrcBuf.mnFormat = ScanlineFormat::TopDown; aSrcBuf.mnWidth = nWidth; aSrcBuf.mnHeight = nHeight; aSrcBuf.mnBitCount = pImage->bits_per_pixel; aSrcBuf.mnScanlineSize = pImage->bytes_per_line; aSrcBuf.mpBits = reinterpret_cast(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 ? ScanlineFormat::N1BitLsbPal : ScanlineFormat::N1BitMsbPal ); } break; case 8: { aSrcBuf.mnFormat |= ScanlineFormat::N8BitPal; } break; case 24: { if( ( LSBFirst == pImage->byte_order ) && ( pImage->red_mask == 0xFF ) ) aSrcBuf.mnFormat |= ScanlineFormat::N24BitTcRgb; else aSrcBuf.mnFormat |= ScanlineFormat::N24BitTcBgr; } break; case 32: { if( LSBFirst == pImage->byte_order ) aSrcBuf.mnFormat |= ( pSalDisp->GetVisual(nScreen).red_mask == 0xFF ? ScanlineFormat::N32BitTcRgba : ScanlineFormat::N32BitTcBgra ); else aSrcBuf.mnFormat |= ( pSalDisp->GetVisual(nScreen).red_mask == 0xFF ? ScanlineFormat::N32BitTcAbgr : ScanlineFormat::N32BitTcArgb ); } break; default: assert(false); } BitmapPalette& rPal = aSrcBuf.maPalette; if( aSrcBuf.mnBitCount == 1 ) { rPal.SetEntryCount( 2 ); rPal[ 0 ] = COL_BLACK; rPal[ 1 ] = COL_WHITE; pDstPal = rPal; } else if( pImage->depth == 8 && bGrey ) { rPal.SetEntryCount( 256 ); for( sal_uInt16 i = 0; i < 256; i++ ) { BitmapColor& rBmpCol = rPal[ i ]; rBmpCol.SetRed( i ); rBmpCol.SetGreen( i ); rBmpCol.SetBlue( i ); } pDstPal = rPal; } else if( aSrcBuf.mnBitCount <= 8 ) { const SalColormap& rColMap = pSalDisp->GetColormap( nScreen ); const sal_uInt16 nCols = std::min(static_cast(rColMap.GetUsed()), sal_uLong(1) << nDrawableDepth); rPal.SetEntryCount( nCols ); for( sal_uInt16 i = 0; i < nCols; i++ ) { const Color nColor( rColMap.GetColor( i ) ); BitmapColor& rBmpCol = rPal[ i ]; rBmpCol.SetRed( nColor.GetRed() ); rBmpCol.SetGreen( nColor.GetGreen() ); rBmpCol.SetBlue( nColor.GetBlue() ); } pDstPal = rPal; } pDIB = StretchAndConvert( aSrcBuf, aTwoRect, aSrcBuf.mnFormat, pDstPal, &aSrcBuf.maColorMask ); XDestroyImage( pImage ); } } return pDIB; } XImage* X11SalBitmap::ImplCreateXImage( SalDisplay const *pSalDisp, SalX11Screen nScreen, tools::Long nDepth, const SalTwoRect& rTwoRect ) const { XImage* pImage = nullptr; if( !mpDIB && mpDDB ) { const_cast(this)->mpDIB = ImplCreateDIB( mpDDB->ImplGetPixmap(), mpDDB->ImplGetScreen(), mpDDB->ImplGetDepth(), 0, 0, mpDDB->ImplGetWidth(), mpDDB->ImplGetHeight(), mbGrey ); } if( mpDIB && mpDIB->mnWidth && mpDIB->mnHeight ) { Display* pXDisp = pSalDisp->GetDisplay(); tools::Long nWidth = rTwoRect.mnDestWidth; tools::Long nHeight = rTwoRect.mnDestHeight; if( 1 == GetBitCount() ) nDepth = 1; pImage = XCreateImage( pXDisp, pSalDisp->GetVisual( nScreen ).GetVisual(), nDepth, ( 1 == nDepth ) ? XYBitmap :ZPixmap, 0, nullptr, nWidth, nHeight, 32, 0 ); if( pImage ) { std::unique_ptr pDstBuf; ScanlineFormat nDstFormat = ScanlineFormat::TopDown; std::optional xPal; std::unique_ptr xMask; switch( pImage->bits_per_pixel ) { case 1: nDstFormat |= ( LSBFirst == pImage->bitmap_bit_order ? ScanlineFormat::N1BitLsbPal : ScanlineFormat::N1BitMsbPal ); break; case 8: nDstFormat |= ScanlineFormat::N8BitPal; break; case 24: { if( ( LSBFirst == pImage->byte_order ) && ( pImage->red_mask == 0xFF ) ) nDstFormat |= ScanlineFormat::N24BitTcRgb; else nDstFormat |= ScanlineFormat::N24BitTcBgr; } break; case 32: { if( LSBFirst == pImage->byte_order ) nDstFormat |= ( pImage->red_mask == 0xFF ? ScanlineFormat::N32BitTcRgba : ScanlineFormat::N32BitTcBgra ); else nDstFormat |= ( pImage->red_mask == 0xFF ? ScanlineFormat::N32BitTcAbgr : ScanlineFormat::N32BitTcArgb ); } break; default: assert(false); } if( pImage->depth == 1 ) { xPal.emplace(2); (*xPal)[ 0 ] = COL_BLACK; (*xPal)[ 1 ] = COL_WHITE; } else if( pImage->depth == 8 && mbGrey ) { xPal.emplace(256); for( sal_uInt16 i = 0; i < 256; i++ ) { BitmapColor& rBmpCol = (*xPal)[ i ]; rBmpCol.SetRed( i ); rBmpCol.SetGreen( i ); rBmpCol.SetBlue( i ); } } else if( pImage->depth <= 8 ) { const SalColormap& rColMap = pSalDisp->GetColormap( nScreen ); const sal_uInt16 nCols = std::min( static_cast(rColMap.GetUsed()) , static_cast(1 << pImage->depth) ); xPal.emplace(nCols); for( sal_uInt16 i = 0; i < nCols; i++ ) { const Color nColor( rColMap.GetColor( i ) ); BitmapColor& rBmpCol = (*xPal)[ i ]; rBmpCol.SetRed( nColor.GetRed() ); rBmpCol.SetGreen( nColor.GetGreen() ); rBmpCol.SetBlue( nColor.GetBlue() ); } } pDstBuf = StretchAndConvert( *mpDIB, rTwoRect, nDstFormat, xPal, xMask.get() ); xPal.reset(); xMask.reset(); if( pDstBuf && pDstBuf->mpBits ) { #if defined HAVE_VALGRIND_HEADERS if (RUNNING_ON_VALGRIND) blankExtraSpace(pDstBuf.get()); #endif // set data in buffer as data member in pImage pImage->data = reinterpret_cast(pDstBuf->mpBits); } else { XDestroyImage( pImage ); pImage = nullptr; } // note that pDstBuf it deleted here, but that doesn't destroy allocated data in buffer } } return pImage; } bool X11SalBitmap::ImplCreateFromDrawable( Drawable aDrawable, SalX11Screen nScreen, tools::Long nDrawableDepth, tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) { Destroy(); if( aDrawable && nWidth && nHeight && nDrawableDepth ) mpDDB.reset(new ImplSalDDB( aDrawable, nScreen, nDrawableDepth, nX, nY, nWidth, nHeight )); return( mpDDB != nullptr ); } ImplSalDDB* X11SalBitmap::ImplGetDDB( Drawable aDrawable, SalX11Screen nXScreen, tools::Long nDrawableDepth, const SalTwoRect& rTwoRect ) const { if( !mpDDB || !mpDDB->ImplMatches( nXScreen, nDrawableDepth, rTwoRect ) ) { if( mpDDB ) { // do we already have a DIB? if not, create aDIB from current DDB first if( !mpDIB ) { const_cast(this)->mpDIB = ImplCreateDIB( mpDDB->ImplGetPixmap(), mpDDB->ImplGetScreen(), mpDDB->ImplGetDepth(), 0, 0, mpDDB->ImplGetWidth(), mpDDB->ImplGetHeight(), mbGrey ); } mpDDB.reset(); } if( mpCache ) mpCache->ImplRemove( 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 nullptr; // 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( vcl_sal::getSalDisplay(GetGenericUnixSalData()), nXScreen, nDrawableDepth, aTwoRect ); if( pImage ) { mpDDB.reset(new ImplSalDDB( pImage, aDrawable, nXScreen, aTwoRect )); delete[] pImage->data; pImage->data = nullptr; XDestroyImage( pImage ); if( mpCache ) mpCache->ImplAdd( const_cast(this) ); } } return mpDDB.get(); } void X11SalBitmap::ImplDraw( Drawable aDrawable, SalX11Screen nXScreen, tools::Long nDrawableDepth, const SalTwoRect& rTwoRect, const GC& rGC ) const { ImplGetDDB( aDrawable, nXScreen, nDrawableDepth, rTwoRect ); if( mpDDB ) mpDDB->ImplDraw( aDrawable, rTwoRect, rGC ); } bool X11SalBitmap::Create( const Size& rSize, vcl::PixelFormat ePixelFormat, const BitmapPalette& rPal ) { Destroy(); mpDIB = ImplCreateDIB( rSize, ePixelFormat, rPal ); return( mpDIB != nullptr ); } bool X11SalBitmap::Create( const SalBitmap& rSSalBmp ) { Destroy(); auto pX11Bmp = dynamic_cast( &rSSalBmp ); if (!pX11Bmp) return false; const X11SalBitmap& rSalBmp = *pX11Bmp; if( rSalBmp.mpDIB ) { // TODO: reference counting... mpDIB.reset(new BitmapBuffer( *rSalBmp.mpDIB )); // TODO: get rid of this when BitmapBuffer gets copy constructor try { mpDIB->mpBits = new sal_uInt8[ mpDIB->mnScanlineSize * mpDIB->mnHeight ]; #if defined HAVE_VALGRIND_HEADERS if (RUNNING_ON_VALGRIND) blankExtraSpace(mpDIB.get()); #endif } catch (const std::bad_alloc&) { mpDIB.reset(); } 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 != nullptr ) ) || ( rSalBmp.mpDDB && ( mpDDB != nullptr ) ) ); } bool X11SalBitmap::Create( const SalBitmap&, SalGraphics* ) { return false; } bool X11SalBitmap::Create(const SalBitmap&, vcl::PixelFormat /*eNewPixelFormat*/) { return false; } bool X11SalBitmap::Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& rBitmapCanvas, Size& rSize, bool bMask ) { css::uno::Reference< css::beans::XFastPropertySet > xFastPropertySet( rBitmapCanvas, css::uno::UNO_QUERY ); if( xFastPropertySet ) { css::uno::Sequence< css::uno::Any > args; if( xFastPropertySet->getFastPropertyValue(bMask ? 2 : 1) >>= args ) { sal_Int64 pixmapHandle = {}; // spurious -Werror=maybe-uninitialized sal_Int32 depth; if( ( args[1] >>= pixmapHandle ) && ( args[2] >>= depth ) ) { mbGrey = bMask; bool bSuccess = ImplCreateFromDrawable( pixmapHandle, // FIXME: this seems multi-screen broken to me SalX11Screen( 0 ), depth, 0, 0, rSize.Width(), rSize.Height() ); bool bFreePixmap = false; if( bSuccess && (args[0] >>= bFreePixmap) && bFreePixmap ) XFreePixmap( vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetDisplay(), pixmapHandle ); return bSuccess; } } } return false; } void X11SalBitmap::Destroy() { if( mpDIB ) { delete[] mpDIB->mpBits; mpDIB.reset(); } mpDDB.reset(); if( mpCache ) mpCache->ImplRemove( this ); } Size X11SalBitmap::GetSize() const { Size aSize; if( mpDIB ) { aSize.setWidth( mpDIB->mnWidth ); aSize.setHeight( mpDIB->mnHeight ); } else if( mpDDB ) { aSize.setWidth( mpDDB->ImplGetWidth() ); aSize.setHeight( 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( BitmapAccessMode /*nMode*/ ) { if( !mpDIB && mpDDB ) { mpDIB = ImplCreateDIB( mpDDB->ImplGetPixmap(), mpDDB->ImplGetScreen(), mpDDB->ImplGetDepth(), 0, 0, mpDDB->ImplGetWidth(), mpDDB->ImplGetHeight(), mbGrey ); } return mpDIB.get(); } void X11SalBitmap::ReleaseBuffer( BitmapBuffer*, BitmapAccessMode nMode ) { if( nMode == BitmapAccessMode::Write ) { mpDDB.reset(); if( mpCache ) mpCache->ImplRemove( this ); InvalidateChecksum(); } } 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 = reinterpret_cast(mpDDB->ImplGetPixmap()); rData.mnWidth = mpDDB->ImplGetWidth (); rData.mnHeight = mpDDB->ImplGetHeight (); return true; } return false; } bool X11SalBitmap::ScalingSupported() const { return false; } bool X11SalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag /*nScaleFlag*/ ) { return false; } bool X11SalBitmap::Replace( const Color& /*rSearchColor*/, const Color& /*rReplaceColor*/, sal_uInt8 /*nTol*/ ) { return false; } ImplSalDDB::ImplSalDDB( XImage* pImage, Drawable aDrawable, SalX11Screen nXScreen, const SalTwoRect& rTwoRect ) : maPixmap ( 0 ) , maTwoRect ( rTwoRect ) , mnDepth ( pImage->depth ) , mnXScreen ( nXScreen ) { SalDisplay* pSalDisp = vcl_sal::getSalDisplay(GetGenericUnixSalData()); Display* pXDisp = pSalDisp->GetDisplay(); maPixmap = limitXCreatePixmap( pXDisp, aDrawable, ImplGetWidth(), ImplGetHeight(), ImplGetDepth() ); if (!maPixmap) return; 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 ); } ImplSalDDB::ImplSalDDB( Drawable aDrawable, SalX11Screen nXScreen, tools::Long nDrawableDepth, tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) : maTwoRect(0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight) , mnDepth( nDrawableDepth ) , mnXScreen( nXScreen ) { SalDisplay* pSalDisp = vcl_sal::getSalDisplay(GetGenericUnixSalData()); Display* pXDisp = pSalDisp->GetDisplay(); if( (maPixmap = limitXCreatePixmap( 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, nX, nY, nWidth, nHeight, 0, 0, aGC ); XFreeGC( pXDisp, aGC ); } else { maTwoRect.mnSrcWidth = maTwoRect.mnDestWidth = 0; maTwoRect.mnSrcHeight = maTwoRect.mnDestHeight = 0; } } ImplSalDDB::~ImplSalDDB() { if( maPixmap && ImplGetSVData() ) XFreePixmap( vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetDisplay(), maPixmap ); } bool ImplSalDDB::ImplMatches( SalX11Screen nXScreen, tools::Long nDepth, const SalTwoRect& rTwoRect ) const { bool bRet = false; if( ( maPixmap != 0 ) && ( ( mnDepth == nDepth ) || ( 1 == mnDepth ) ) && nXScreen == mnXScreen) { 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 identically bRet = 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 = true; } } return bRet; } void ImplSalDDB::ImplDraw( Drawable aDrawable, const SalTwoRect& rTwoRect, const GC& rGC ) const { ImplDraw( maPixmap, mnDepth, aDrawable, rTwoRect.mnSrcX - maTwoRect.mnSrcX, rTwoRect.mnSrcY - maTwoRect.mnSrcY, rTwoRect.mnDestWidth, rTwoRect.mnDestHeight, rTwoRect.mnDestX, rTwoRect.mnDestY, rGC ); } void ImplSalDDB::ImplDraw( Drawable aSrcDrawable, tools::Long nSrcDrawableDepth, Drawable aDstDrawable, tools::Long nSrcX, tools::Long nSrcY, tools::Long nDestWidth, tools::Long nDestHeight, tools::Long nDestX, tools::Long nDestY, const GC& rGC ) { SalDisplay* pSalDisp = vcl_sal::getSalDisplay(GetGenericUnixSalData()); 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::ImplSalBitmapCache() { } ImplSalBitmapCache::~ImplSalBitmapCache() { ImplClear(); } void ImplSalBitmapCache::ImplAdd( X11SalBitmap* pBmp ) { for(auto pObj : maBmpList) { if( pObj == pBmp ) return; } maBmpList.push_back( pBmp ); } void ImplSalBitmapCache::ImplRemove( X11SalBitmap const * pBmp ) { auto it = std::find(maBmpList.begin(), maBmpList.end(), pBmp); if( it != maBmpList.end() ) { (*it)->ImplRemovedFromCache(); maBmpList.erase( it ); } } void ImplSalBitmapCache::ImplClear() { for(auto pObj : maBmpList) { pObj->ImplRemovedFromCache(); } maBmpList.clear(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */