From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- vcl/unx/generic/gdi/salbmp.cxx | 1001 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1001 insertions(+) create mode 100644 vcl/unx/generic/gdi/salbmp.cxx (limited to 'vcl/unx/generic/gdi/salbmp.cxx') diff --git a/vcl/unx/generic/gdi/salbmp.cxx b/vcl/unx/generic/gdi/salbmp.cxx new file mode 100644 index 000000000..804b50184 --- /dev/null +++ b/vcl/unx/generic/gdi/salbmp.cxx @@ -0,0 +1,1001 @@ +/* -*- 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: */ -- cgit v1.2.3