diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /vcl/source/helper | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vcl/source/helper')
-rw-r--r-- | vcl/source/helper/canvasbitmap.cxx | 1346 | ||||
-rw-r--r-- | vcl/source/helper/canvastools.cxx | 627 | ||||
-rw-r--r-- | vcl/source/helper/commandinfoprovider.cxx | 477 | ||||
-rw-r--r-- | vcl/source/helper/displayconnectiondispatch.cxx | 111 | ||||
-rw-r--r-- | vcl/source/helper/driverblocklist.cxx | 769 | ||||
-rw-r--r-- | vcl/source/helper/evntpost.cxx | 57 | ||||
-rw-r--r-- | vcl/source/helper/idletask.cxx | 51 | ||||
-rw-r--r-- | vcl/source/helper/lazydelete.cxx | 58 | ||||
-rw-r--r-- | vcl/source/helper/strhelper.cxx | 380 | ||||
-rw-r--r-- | vcl/source/helper/svtaccessiblefactory.cxx | 289 | ||||
-rw-r--r-- | vcl/source/helper/threadex.cxx | 68 |
11 files changed, 4233 insertions, 0 deletions
diff --git a/vcl/source/helper/canvasbitmap.cxx b/vcl/source/helper/canvasbitmap.cxx new file mode 100644 index 0000000000..f2e0f7889c --- /dev/null +++ b/vcl/source/helper/canvasbitmap.cxx @@ -0,0 +1,1346 @@ +/* -*- 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 <sal/config.h> + +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/util/Endianness.hpp> +#include <com/sun/star/rendering/ColorComponentTag.hpp> +#include <com/sun/star/rendering/ColorSpaceType.hpp> +#include <com/sun/star/rendering/RenderingIntent.hpp> + +#include <comphelper/diagnose_ex.hxx> +#include <canvasbitmap.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/BitmapReadAccess.hxx> +#include <vcl/svapp.hxx> + +#include <algorithm> + +using namespace vcl::unotools; +using namespace ::com::sun::star; + +namespace +{ + // TODO(Q3): move to o3tl bithacks or somesuch. A similar method is in canvas/canvastools.hxx + + // Good ole HAKMEM tradition. Calc number of 1 bits in 32bit word, + // unrolled loop. See e.g. Hackers Delight, p. 66 + sal_Int32 bitcount( sal_uInt32 val ) + { + val = val - ((val >> 1) & 0x55555555); + val = (val & 0x33333333) + ((val >> 2) & 0x33333333); + val = (val + (val >> 4)) & 0x0F0F0F0F; + val = val + (val >> 8); + val = val + (val >> 16); + return sal_Int32(val & 0x0000003F); + } +} + +void VclCanvasBitmap::setComponentInfo( sal_uInt32 redShift, sal_uInt32 greenShift, sal_uInt32 blueShift ) +{ + // sort channels in increasing order of appearance in the pixel + // (starting with the least significant bits) + sal_Int8 redPos(0); + sal_Int8 greenPos(1); + sal_Int8 bluePos(2); + + if( redShift > greenShift ) + { + std::swap(redPos,greenPos); + if( redShift > blueShift ) + { + std::swap(redPos,bluePos); + if( greenShift > blueShift ) + std::swap(greenPos,bluePos); + } + } + else + { + if( greenShift > blueShift ) + { + std::swap(greenPos,bluePos); + if( redShift > blueShift ) + std::swap(redPos,bluePos); + } + } + + m_aComponentTags.realloc(3); + sal_Int8* pTags = m_aComponentTags.getArray(); + pTags[redPos] = rendering::ColorComponentTag::RGB_RED; + pTags[greenPos] = rendering::ColorComponentTag::RGB_GREEN; + pTags[bluePos] = rendering::ColorComponentTag::RGB_BLUE; + + m_aComponentBitCounts.realloc(3); + sal_Int32* pCounts = m_aComponentBitCounts.getArray(); + pCounts[redPos] = bitcount(redShift); + pCounts[greenPos] = bitcount(greenShift); + pCounts[bluePos] = bitcount(blueShift); +} + +BitmapScopedReadAccess& VclCanvasBitmap::getBitmapReadAccess() +{ + // BitmapReadAccess is more expensive than BitmapInfoAccess, + // as the latter requires also pixels, which may need converted + // from the system format (and even fetched). Most calls here + // need only info access, create read access only on demand. + if(!m_pBmpReadAcc) + m_pBmpReadAcc.emplace(m_aBitmap); + return *m_pBmpReadAcc; +} + +BitmapScopedReadAccess& VclCanvasBitmap::getAlphaReadAccess() +{ + if(!m_pAlphaReadAcc) + m_pAlphaReadAcc.emplace(m_aAlpha); + return *m_pAlphaReadAcc; +} + +VclCanvasBitmap::VclCanvasBitmap( const BitmapEx& rBitmap ) : + m_aBmpEx( rBitmap ), + m_aBitmap( rBitmap.GetBitmap() ), + m_pBmpAcc( m_aBitmap ), + m_nBitsPerInputPixel(0), + m_nBitsPerOutputPixel(0), + m_nRedIndex(-1), + m_nGreenIndex(-1), + m_nBlueIndex(-1), + m_nAlphaIndex(-1), + m_nIndexIndex(-1), + m_bPalette(false) +{ + if( m_aBmpEx.IsAlpha() ) + { + m_aAlpha = m_aBmpEx.GetAlphaMask().GetBitmap(); + m_pAlphaAcc = m_aAlpha; + } + + m_aLayout.ScanLines = 0; + m_aLayout.ScanLineBytes = 0; + m_aLayout.ScanLineStride = 0; + m_aLayout.PlaneStride = 0; + m_aLayout.ColorSpace.clear(); + m_aLayout.Palette.clear(); + m_aLayout.IsMsbFirst = false; + + if( !m_pBmpAcc ) + return; + + m_aLayout.ScanLines = m_pBmpAcc->Height(); + m_aLayout.ScanLineBytes = (m_pBmpAcc->GetBitCount()*m_pBmpAcc->Width() + 7) / 8; + m_aLayout.ScanLineStride = m_pBmpAcc->GetScanlineSize(); + m_aLayout.PlaneStride = 0; + + switch( m_pBmpAcc->GetScanlineFormat() ) + { + case ScanlineFormat::N1BitMsbPal: + m_bPalette = true; + m_nBitsPerInputPixel = 1; + m_aLayout.IsMsbFirst = true; + break; + + case ScanlineFormat::N8BitPal: + m_bPalette = true; + m_nBitsPerInputPixel = 8; + m_aLayout.IsMsbFirst = false; // doesn't matter + break; + + case ScanlineFormat::N24BitTcBgr: + m_bPalette = false; + m_nBitsPerInputPixel = 24; + m_aLayout.IsMsbFirst = false; // doesn't matter + setComponentInfo( static_cast<sal_uInt32>(0xff0000UL), + static_cast<sal_uInt32>(0x00ff00UL), + static_cast<sal_uInt32>(0x0000ffUL) ); + break; + + case ScanlineFormat::N24BitTcRgb: + m_bPalette = false; + m_nBitsPerInputPixel = 24; + m_aLayout.IsMsbFirst = false; // doesn't matter + setComponentInfo( static_cast<sal_uInt32>(0x0000ffUL), + static_cast<sal_uInt32>(0x00ff00UL), + static_cast<sal_uInt32>(0xff0000UL) ); + break; + + case ScanlineFormat::N32BitTcAbgr: + { + m_bPalette = false; + m_nBitsPerInputPixel = 32; + m_aLayout.IsMsbFirst = false; // doesn't matter + + m_aComponentTags = { /* 0 */ rendering::ColorComponentTag::ALPHA, + /* 1 */ rendering::ColorComponentTag::RGB_BLUE, + /* 2 */ rendering::ColorComponentTag::RGB_GREEN, + /* 3 */ rendering::ColorComponentTag::RGB_RED }; + + m_aComponentBitCounts = { /* 0 */ 8, + /* 1 */ 8, + /* 2 */ 8, + /* 3 */ 8 }; + + m_nRedIndex = 3; + m_nGreenIndex = 2; + m_nBlueIndex = 1; + m_nAlphaIndex = 0; + } + break; + + case ScanlineFormat::N32BitTcArgb: + { + m_bPalette = false; + m_nBitsPerInputPixel = 32; + m_aLayout.IsMsbFirst = false; // doesn't matter + + m_aComponentTags = { /* 0 */ rendering::ColorComponentTag::ALPHA, + /* 1 */ rendering::ColorComponentTag::RGB_RED, + /* 2 */ rendering::ColorComponentTag::RGB_GREEN, + /* 3 */ rendering::ColorComponentTag::RGB_BLUE }; + + m_aComponentBitCounts = { /* 0 */ 8, + /* 1 */ 8, + /* 2 */ 8, + /* 3 */ 8 }; + + m_nRedIndex = 1; + m_nGreenIndex = 2; + m_nBlueIndex = 3; + m_nAlphaIndex = 0; + } + break; + + case ScanlineFormat::N32BitTcBgra: + { + m_bPalette = false; + m_nBitsPerInputPixel = 32; + m_aLayout.IsMsbFirst = false; // doesn't matter + + m_aComponentTags = { /* 0 */ rendering::ColorComponentTag::RGB_BLUE, + /* 1 */ rendering::ColorComponentTag::RGB_GREEN, + /* 2 */ rendering::ColorComponentTag::RGB_RED, + /* 3 */ rendering::ColorComponentTag::ALPHA }; + + m_aComponentBitCounts = { /* 0 */ 8, + /* 1 */ 8, + /* 2 */ 8, + /* 3 */ 8 }; + + m_nRedIndex = 2; + m_nGreenIndex = 1; + m_nBlueIndex = 0; + m_nAlphaIndex = 3; + } + break; + + case ScanlineFormat::N32BitTcRgba: + { + m_bPalette = false; + m_nBitsPerInputPixel = 32; + m_aLayout.IsMsbFirst = false; // doesn't matter + + m_aComponentTags = { /* 0 */ rendering::ColorComponentTag::RGB_RED, + /* 1 */ rendering::ColorComponentTag::RGB_GREEN, + /* 2 */ rendering::ColorComponentTag::RGB_BLUE, + /* 3 */ rendering::ColorComponentTag::ALPHA }; + + m_aComponentBitCounts = { /* 0 */ 8, + /* 1 */ 8, + /* 2 */ 8, + /* 3 */ 8 }; + + m_nRedIndex = 0; + m_nGreenIndex = 1; + m_nBlueIndex = 2; + m_nAlphaIndex = 3; + } + break; + + case ScanlineFormat::N32BitTcMask: + m_bPalette = false; + m_nBitsPerInputPixel = 32; + m_aLayout.IsMsbFirst = false; // doesn't matter + setComponentInfo( m_pBmpAcc->GetColorMask().GetRedMask(), + m_pBmpAcc->GetColorMask().GetGreenMask(), + m_pBmpAcc->GetColorMask().GetBlueMask() ); + break; + + default: + OSL_FAIL( "unsupported bitmap format" ); + break; + } + + if( m_bPalette ) + { + m_aComponentTags = { rendering::ColorComponentTag::INDEX }; + + m_aComponentBitCounts = { m_nBitsPerInputPixel }; + + m_nIndexIndex = 0; + } + + m_nBitsPerOutputPixel = m_nBitsPerInputPixel; + if( !m_aBmpEx.IsAlpha() ) + return; + + // TODO(P1): need to interleave alpha with bitmap data - + // won't fuss with less-than-8 bit for now + m_nBitsPerOutputPixel = std::max(sal_Int32(8),m_nBitsPerInputPixel); + + // check whether alpha goes in front or behind the + // bitcount sequence. If pixel format is little endian, + // put it behind all the other channels. If it's big + // endian, put it in front (because later, the actual data + // always gets written after the pixel data) + + // TODO(Q1): slight catch - in the case of the + // BMP_FORMAT_32BIT_XX_ARGB formats, duplicate alpha + // channels might happen! + m_aComponentTags.realloc(m_aComponentTags.getLength()+1); + m_aComponentTags.getArray()[m_aComponentTags.getLength()-1] = rendering::ColorComponentTag::ALPHA; + + m_aComponentBitCounts.realloc(m_aComponentBitCounts.getLength()+1); + m_aComponentBitCounts.getArray()[m_aComponentBitCounts.getLength()-1] = m_aBmpEx.IsAlpha() ? 8 : 1; + + // always add a full byte to the pixel size, otherwise + // pixel packing hell breaks loose. + m_nBitsPerOutputPixel += 8; + + // adapt scanline parameters + const Size aSize = m_aBitmap.GetSizePixel(); + m_aLayout.ScanLineBytes = + m_aLayout.ScanLineStride = (aSize.Width()*m_nBitsPerOutputPixel + 7)/8; +} + +VclCanvasBitmap::~VclCanvasBitmap() +{ +} + +// XBitmap +geometry::IntegerSize2D SAL_CALL VclCanvasBitmap::getSize() +{ + SolarMutexGuard aGuard; + return integerSize2DFromSize( m_aBitmap.GetSizePixel() ); +} + +sal_Bool SAL_CALL VclCanvasBitmap::hasAlpha() +{ + SolarMutexGuard aGuard; + return m_aBmpEx.IsAlpha(); +} + +uno::Reference< rendering::XBitmap > SAL_CALL VclCanvasBitmap::getScaledBitmap( const geometry::RealSize2D& newSize, + sal_Bool beFast ) +{ + SolarMutexGuard aGuard; + + BitmapEx aNewBmp( m_aBitmap ); + aNewBmp.Scale( sizeFromRealSize2D( newSize ), beFast ? BmpScaleFlag::Default : BmpScaleFlag::BestQuality ); + return uno::Reference<rendering::XBitmap>( new VclCanvasBitmap( aNewBmp ) ); +} + +// XIntegerReadOnlyBitmap +uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getData( rendering::IntegerBitmapLayout& bitmapLayout, + const geometry::IntegerRectangle2D& rect ) +{ + SolarMutexGuard aGuard; + + bitmapLayout = getMemoryLayout(); + + const ::tools::Rectangle aRequestedArea( vcl::unotools::rectangleFromIntegerRectangle2D(rect) ); + if( aRequestedArea.IsEmpty() ) + return uno::Sequence< sal_Int8 >(); + + // Invalid/empty bitmap: no data available + if( !m_pBmpAcc ) + throw lang::IndexOutOfBoundsException(); + if( m_aBmpEx.IsAlpha() && !m_pAlphaAcc ) + throw lang::IndexOutOfBoundsException(); + + if( aRequestedArea.Left() < 0 || aRequestedArea.Top() < 0 || + aRequestedArea.Right() > m_pBmpAcc->Width() || + aRequestedArea.Bottom() > m_pBmpAcc->Height() ) + { + throw lang::IndexOutOfBoundsException(); + } + + uno::Sequence< sal_Int8 > aRet; + tools::Rectangle aRequestedBytes( aRequestedArea ); + + // adapt to byte boundaries + aRequestedBytes.SetLeft( aRequestedArea.Left()*m_nBitsPerOutputPixel/8 ); + aRequestedBytes.SetRight( (aRequestedArea.Right()*m_nBitsPerOutputPixel + 7)/8 ); + + // copy stuff to output sequence + aRet.realloc(aRequestedBytes.getOpenWidth()*aRequestedBytes.getOpenHeight()); + sal_Int8* pOutBuf = aRet.getArray(); + + bitmapLayout.ScanLines = aRequestedBytes.getOpenHeight(); + bitmapLayout.ScanLineBytes = + bitmapLayout.ScanLineStride= aRequestedBytes.getOpenWidth(); + + sal_Int32 nScanlineStride=bitmapLayout.ScanLineStride; + if( !(m_pBmpAcc->GetScanlineFormat() & ScanlineFormat::TopDown) ) + { + pOutBuf += bitmapLayout.ScanLineStride*(aRequestedBytes.getOpenHeight()-1); + nScanlineStride *= -1; + } + + if( !m_aBmpEx.IsAlpha() ) + { + BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess(); + OSL_ENSURE(pBmpAcc,"Invalid bmp read access"); + + // can return bitmap data as-is + for( tools::Long y=aRequestedBytes.Top(); y<aRequestedBytes.Bottom(); ++y ) + { + Scanline pScan = pBmpAcc->GetScanline(y); + memcpy(pOutBuf, pScan+aRequestedBytes.Left(), aRequestedBytes.getOpenWidth()); + pOutBuf += nScanlineStride; + } + } + else + { + BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess(); + BitmapScopedReadAccess& pAlphaAcc = getAlphaReadAccess(); + OSL_ENSURE(pBmpAcc,"Invalid bmp read access"); + OSL_ENSURE(pAlphaAcc,"Invalid alpha read access"); + + // interleave alpha with bitmap data - note, bitcount is + // always integer multiple of 8 + OSL_ENSURE((m_nBitsPerOutputPixel & 0x07) == 0, + "Transparent bitmap bitcount not integer multiple of 8" ); + + for( tools::Long y=aRequestedArea.Top(); y<aRequestedArea.Bottom(); ++y ) + { + sal_Int8* pOutScan = pOutBuf; + + if( m_nBitsPerInputPixel < 8 ) + { + // input less than a byte - copy via GetPixel() + for( tools::Long x=aRequestedArea.Left(); x<aRequestedArea.Right(); ++x ) + { + *pOutScan++ = pBmpAcc->GetPixelIndex(y,x); + // vcl used to store transparency. Now it stores alpha. But we need the UNO + // interface to still preserve the old interface. + *pOutScan++ = 255 - pAlphaAcc->GetPixelIndex(y,x); + } + } + else + { + const tools::Long nNonAlphaBytes( m_nBitsPerInputPixel/8 ); + const tools::Long nScanlineOffsetLeft(aRequestedArea.Left()*nNonAlphaBytes); + Scanline pScan = pBmpAcc->GetScanline(y) + nScanlineOffsetLeft; + Scanline pScanlineAlpha = pAlphaAcc->GetScanline( y ); + + // input integer multiple of byte - copy directly + for( tools::Long x=aRequestedArea.Left(); x<aRequestedArea.Right(); ++x ) + { + for( tools::Long i=0; i<nNonAlphaBytes; ++i ) + *pOutScan++ = *pScan++; + // vcl used to store transparency. Now it stores alpha. But we need the UNO + // interface to still preserve the old interface. + *pOutScan++ = 255 - pAlphaAcc->GetIndexFromData( pScanlineAlpha, x ); + } + } + + pOutBuf += nScanlineStride; + } + } + + return aRet; +} + +uno::Sequence< sal_Int8 > SAL_CALL VclCanvasBitmap::getPixel( rendering::IntegerBitmapLayout& bitmapLayout, + const geometry::IntegerPoint2D& pos ) +{ + SolarMutexGuard aGuard; + + bitmapLayout = getMemoryLayout(); + + // Invalid/empty bitmap: no data available + if( !m_pBmpAcc ) + throw lang::IndexOutOfBoundsException(); + if( m_aBmpEx.IsAlpha() && !m_pAlphaAcc ) + throw lang::IndexOutOfBoundsException(); + + if( pos.X < 0 || pos.Y < 0 || + pos.X > m_pBmpAcc->Width() || pos.Y > m_pBmpAcc->Height() ) + { + throw lang::IndexOutOfBoundsException(); + } + + uno::Sequence< sal_Int8 > aRet((m_nBitsPerOutputPixel + 7)/8); + sal_Int8* pOutBuf = aRet.getArray(); + + // copy stuff to output sequence + bitmapLayout.ScanLines = 1; + bitmapLayout.ScanLineBytes = + bitmapLayout.ScanLineStride= aRet.getLength(); + + const tools::Long nScanlineLeftOffset( pos.X*m_nBitsPerInputPixel/8 ); + if( !m_aBmpEx.IsAlpha() ) + { + BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess(); + assert(pBmpAcc && "Invalid bmp read access"); + + // can return bitmap data as-is + Scanline pScan = pBmpAcc->GetScanline(pos.Y); + memcpy(pOutBuf, pScan+nScanlineLeftOffset, aRet.getLength() ); + } + else + { + BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess(); + BitmapScopedReadAccess& pAlphaAcc = getAlphaReadAccess(); + assert(pBmpAcc && "Invalid bmp read access"); + assert(pAlphaAcc && "Invalid alpha read access"); + + // interleave alpha with bitmap data - note, bitcount is + // always integer multiple of 8 + assert((m_nBitsPerOutputPixel & 0x07) == 0 && + "Transparent bitmap bitcount not integer multiple of 8" ); + + if( m_nBitsPerInputPixel < 8 ) + { + // input less than a byte - copy via GetPixel() + *pOutBuf++ = pBmpAcc->GetPixelIndex(pos.Y,pos.X); + // vcl used to store transparency. Now it stores alpha. But we need the UNO + // interface to still preserve the old interface. + *pOutBuf = 255 - pAlphaAcc->GetPixelIndex(pos.Y,pos.X); + } + else + { + const tools::Long nNonAlphaBytes( m_nBitsPerInputPixel/8 ); + Scanline pScan = pBmpAcc->GetScanline(pos.Y); + + // input integer multiple of byte - copy directly + memcpy(pOutBuf, pScan+nScanlineLeftOffset, nNonAlphaBytes ); + pOutBuf += nNonAlphaBytes; + // vcl used to store transparency. Now it stores alpha. But we need the UNO + // interface to still preserve the old interface. + *pOutBuf++ = 255 - pAlphaAcc->GetPixelIndex(pos.Y,pos.X); + } + } + + return aRet; +} + +uno::Reference< rendering::XBitmapPalette > VclCanvasBitmap::getPalette() +{ + SolarMutexGuard aGuard; + + uno::Reference< XBitmapPalette > aRet; + if( m_bPalette ) + aRet.set(this); + + return aRet; +} + +rendering::IntegerBitmapLayout SAL_CALL VclCanvasBitmap::getMemoryLayout() +{ + SolarMutexGuard aGuard; + + rendering::IntegerBitmapLayout aLayout( m_aLayout ); + + // only set references to self on separate copy of + // IntegerBitmapLayout - if we'd set that on m_aLayout, we'd have + // a circular reference! + if( m_bPalette ) + aLayout.Palette.set( this ); + + aLayout.ColorSpace.set( this ); + + return aLayout; +} + +sal_Int32 SAL_CALL VclCanvasBitmap::getNumberOfEntries() +{ + SolarMutexGuard aGuard; + + if( !m_pBmpAcc ) + return 0; + + return m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ; +} + +sal_Bool SAL_CALL VclCanvasBitmap::getIndex( uno::Sequence< double >& o_entry, sal_Int32 nIndex ) +{ + SolarMutexGuard aGuard; + + const sal_uInt16 nCount( m_pBmpAcc ? + (m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ) : 0 ); + OSL_ENSURE(nIndex >= 0 && nIndex < nCount,"Palette index out of range"); + if( nIndex < 0 || nIndex >= nCount ) + throw lang::IndexOutOfBoundsException("Palette index out of range", + static_cast<rendering::XBitmapPalette*>(this)); + + const BitmapColor aCol = m_pBmpAcc->GetPaletteColor(sal::static_int_cast<sal_uInt16>(nIndex)); + o_entry.realloc(3); + double* pColor=o_entry.getArray(); + pColor[0] = aCol.GetRed(); + pColor[1] = aCol.GetGreen(); + pColor[2] = aCol.GetBlue(); + + return true; // no palette transparency here. +} + +sal_Bool SAL_CALL VclCanvasBitmap::setIndex( const uno::Sequence< double >&, sal_Bool, sal_Int32 nIndex ) +{ + SolarMutexGuard aGuard; + + const sal_uInt16 nCount( m_pBmpAcc ? + (m_pBmpAcc->HasPalette() ? m_pBmpAcc->GetPaletteEntryCount() : 0 ) : 0 ); + + OSL_ENSURE(nIndex >= 0 && nIndex < nCount,"Palette index out of range"); + if( nIndex < 0 || nIndex >= nCount ) + throw lang::IndexOutOfBoundsException("Palette index out of range", + static_cast<rendering::XBitmapPalette*>(this)); + + return false; // read-only implementation +} + +uno::Reference< rendering::XColorSpace > SAL_CALL VclCanvasBitmap::getColorSpace( ) +{ + // this is the method from XBitmapPalette. Return palette color + // space here + static uno::Reference<rendering::XColorSpace> gColorSpace = vcl::unotools::createStandardColorSpace(); + return gColorSpace; +} + +sal_Int8 SAL_CALL VclCanvasBitmap::getType( ) +{ + return rendering::ColorSpaceType::RGB; +} + +uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::getComponentTags( ) +{ + SolarMutexGuard aGuard; + return m_aComponentTags; +} + +sal_Int8 SAL_CALL VclCanvasBitmap::getRenderingIntent( ) +{ + return rendering::RenderingIntent::PERCEPTUAL; +} + +uno::Sequence< ::beans::PropertyValue > SAL_CALL VclCanvasBitmap::getProperties( ) +{ + return uno::Sequence< ::beans::PropertyValue >(); +} + +uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertColorSpace( const uno::Sequence< double >& deviceColor, + const uno::Reference< ::rendering::XColorSpace >& targetColorSpace ) +{ + // TODO(P3): if we know anything about target + // colorspace, this can be greatly sped up + uno::Sequence<rendering::ARGBColor> aIntermediate( + convertToARGB(deviceColor)); + return targetColorSpace->convertFromARGB(aIntermediate); +} + +uno::Sequence<rendering::RGBColor> SAL_CALL VclCanvasBitmap::convertToRGB( const uno::Sequence< double >& deviceColor ) +{ + SolarMutexGuard aGuard; + + const std::size_t nLen( deviceColor.getLength() ); + const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); + ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0, + "number of channels no multiple of pixel element count", + static_cast<rendering::XBitmapPalette*>(this), 01); + + uno::Sequence< rendering::RGBColor > aRes(nLen/nComponentsPerPixel); + rendering::RGBColor* pOut( aRes.getArray() ); + + if( m_bPalette ) + { + OSL_ENSURE(m_nIndexIndex != -1, + "Invalid color channel indices"); + ENSURE_OR_THROW(m_pBmpAcc, + "Unable to get BitmapAccess"); + + for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel ) + { + const BitmapColor aCol = m_pBmpAcc->GetPaletteColor( + sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex])); + + // TODO(F3): Convert result to sRGB color space + *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()), + toDoubleColor(aCol.GetGreen()), + toDoubleColor(aCol.GetBlue())); + } + } + else + { + OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1, + "Invalid color channel indices"); + + for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel ) + { + // TODO(F3): Convert result to sRGB color space + *pOut++ = rendering::RGBColor( + deviceColor[i+m_nRedIndex], + deviceColor[i+m_nGreenIndex], + deviceColor[i+m_nBlueIndex]); + } + } + + return aRes; +} + +uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertToARGB( const uno::Sequence< double >& deviceColor ) +{ + SolarMutexGuard aGuard; + + const std::size_t nLen( deviceColor.getLength() ); + const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); + ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0, + "number of channels no multiple of pixel element count", + static_cast<rendering::XBitmapPalette*>(this), 01); + + uno::Sequence< rendering::ARGBColor > aRes(nLen/nComponentsPerPixel); + rendering::ARGBColor* pOut( aRes.getArray() ); + + if( m_bPalette ) + { + OSL_ENSURE(m_nIndexIndex != -1, + "Invalid color channel indices"); + ENSURE_OR_THROW(m_pBmpAcc, + "Unable to get BitmapAccess"); + + for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel ) + { + const BitmapColor aCol = m_pBmpAcc->GetPaletteColor( + sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex])); + + // TODO(F3): Convert result to sRGB color space + const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 ); + *pOut++ = rendering::ARGBColor(nAlpha, + toDoubleColor(aCol.GetRed()), + toDoubleColor(aCol.GetGreen()), + toDoubleColor(aCol.GetBlue())); + } + } + else + { + OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1, + "Invalid color channel indices"); + + for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel ) + { + // TODO(F3): Convert result to sRGB color space + const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 ); + *pOut++ = rendering::ARGBColor( + nAlpha, + deviceColor[i+m_nRedIndex], + deviceColor[i+m_nGreenIndex], + deviceColor[i+m_nBlueIndex]); + } + } + + return aRes; +} + +uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertToPARGB( const uno::Sequence< double >& deviceColor ) +{ + SolarMutexGuard aGuard; + + const std::size_t nLen( deviceColor.getLength() ); + const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); + ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0, + "number of channels no multiple of pixel element count", + static_cast<rendering::XBitmapPalette*>(this), 01); + + uno::Sequence< rendering::ARGBColor > aRes(nLen/nComponentsPerPixel); + rendering::ARGBColor* pOut( aRes.getArray() ); + + if( m_bPalette ) + { + OSL_ENSURE(m_nIndexIndex != -1, + "Invalid color channel indices"); + ENSURE_OR_THROW(m_pBmpAcc, + "Unable to get BitmapAccess"); + + for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel ) + { + const BitmapColor aCol = m_pBmpAcc->GetPaletteColor( + sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex])); + + // TODO(F3): Convert result to sRGB color space + const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 ); + *pOut++ = rendering::ARGBColor(nAlpha, + nAlpha*toDoubleColor(aCol.GetRed()), + nAlpha*toDoubleColor(aCol.GetGreen()), + nAlpha*toDoubleColor(aCol.GetBlue())); + } + } + else + { + OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1, + "Invalid color channel indices"); + + for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel ) + { + // TODO(F3): Convert result to sRGB color space + const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 ); + *pOut++ = rendering::ARGBColor( + nAlpha, + nAlpha*deviceColor[i+m_nRedIndex], + nAlpha*deviceColor[i+m_nGreenIndex], + nAlpha*deviceColor[i+m_nBlueIndex]); + } + } + + return aRes; +} + +uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromRGB( const uno::Sequence<rendering::RGBColor>& rgbColor ) +{ + SolarMutexGuard aGuard; + + const std::size_t nLen( rgbColor.getLength() ); + const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); + + uno::Sequence< double > aRes(nLen*nComponentsPerPixel); + double* pColors=aRes.getArray(); + + if( m_bPalette ) + { + for( const auto& rIn : rgbColor ) + { + pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex( + BitmapColor(toByteColor(rIn.Red), + toByteColor(rIn.Green), + toByteColor(rIn.Blue))); + if( m_nAlphaIndex != -1 ) + pColors[m_nAlphaIndex] = 1.0; + + pColors += nComponentsPerPixel; + } + } + else + { + for( const auto& rIn : rgbColor ) + { + pColors[m_nRedIndex] = rIn.Red; + pColors[m_nGreenIndex] = rIn.Green; + pColors[m_nBlueIndex] = rIn.Blue; + if( m_nAlphaIndex != -1 ) + pColors[m_nAlphaIndex] = 1.0; + + pColors += nComponentsPerPixel; + } + } + return aRes; +} + +uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) +{ + SolarMutexGuard aGuard; + + const std::size_t nLen( rgbColor.getLength() ); + const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); + + uno::Sequence< double > aRes(nLen*nComponentsPerPixel); + double* pColors=aRes.getArray(); + + if( m_bPalette ) + { + for( const auto& rIn : rgbColor ) + { + pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex( + BitmapColor(toByteColor(rIn.Red), + toByteColor(rIn.Green), + toByteColor(rIn.Blue))); + if( m_nAlphaIndex != -1 ) + pColors[m_nAlphaIndex] = rIn.Alpha; + + pColors += nComponentsPerPixel; + } + } + else + { + for( const auto& rIn : rgbColor ) + { + pColors[m_nRedIndex] = rIn.Red; + pColors[m_nGreenIndex] = rIn.Green; + pColors[m_nBlueIndex] = rIn.Blue; + if( m_nAlphaIndex != -1 ) + pColors[m_nAlphaIndex] = rIn.Alpha; + + pColors += nComponentsPerPixel; + } + } + return aRes; +} + +uno::Sequence< double > SAL_CALL VclCanvasBitmap::convertFromPARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) +{ + SolarMutexGuard aGuard; + + const std::size_t nLen( rgbColor.getLength() ); + const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); + + uno::Sequence< double > aRes(nLen*nComponentsPerPixel); + double* pColors=aRes.getArray(); + + if( m_bPalette ) + { + for( const auto& rIn : rgbColor ) + { + const double nAlpha( rIn.Alpha ); + pColors[m_nIndexIndex] = m_pBmpAcc->GetBestPaletteIndex( + BitmapColor(toByteColor(rIn.Red / nAlpha), + toByteColor(rIn.Green / nAlpha), + toByteColor(rIn.Blue / nAlpha))); + if( m_nAlphaIndex != -1 ) + pColors[m_nAlphaIndex] = nAlpha; + + pColors += nComponentsPerPixel; + } + } + else + { + for( const auto& rIn : rgbColor ) + { + const double nAlpha( rIn.Alpha ); + pColors[m_nRedIndex] = rIn.Red / nAlpha; + pColors[m_nGreenIndex] = rIn.Green / nAlpha; + pColors[m_nBlueIndex] = rIn.Blue / nAlpha; + if( m_nAlphaIndex != -1 ) + pColors[m_nAlphaIndex] = nAlpha; + + pColors += nComponentsPerPixel; + } + } + return aRes; +} + +sal_Int32 SAL_CALL VclCanvasBitmap::getBitsPerPixel( ) +{ + return m_nBitsPerOutputPixel; +} + +uno::Sequence< ::sal_Int32 > SAL_CALL VclCanvasBitmap::getComponentBitCounts( ) +{ + return m_aComponentBitCounts; +} + +sal_Int8 SAL_CALL VclCanvasBitmap::getEndianness( ) +{ + return util::Endianness::LITTLE; +} + +uno::Sequence<double> SAL_CALL VclCanvasBitmap::convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor, + const uno::Reference< ::rendering::XColorSpace >& targetColorSpace ) +{ + if( dynamic_cast<VclCanvasBitmap*>(targetColorSpace.get()) ) + { + SolarMutexGuard aGuard; + + const std::size_t nLen( deviceColor.getLength() ); + const sal_Int32 nComponentsPerPixel(m_aComponentTags.getLength()); + ENSURE_ARG_OR_THROW2(nLen%nComponentsPerPixel==0, + "number of channels no multiple of pixel element count", + static_cast<rendering::XBitmapPalette*>(this), 01); + + uno::Sequence<double> aRes(nLen); + double* pOut( aRes.getArray() ); + + if( m_bPalette ) + { + OSL_ENSURE(m_nIndexIndex != -1, + "Invalid color channel indices"); + ENSURE_OR_THROW(m_pBmpAcc, + "Unable to get BitmapAccess"); + + for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel ) + { + const BitmapColor aCol = m_pBmpAcc->GetPaletteColor( + sal::static_int_cast<sal_uInt16>(deviceColor[i+m_nIndexIndex])); + + // TODO(F3): Convert result to sRGB color space + const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 ); + *pOut++ = toDoubleColor(aCol.GetRed()); + *pOut++ = toDoubleColor(aCol.GetGreen()); + *pOut++ = toDoubleColor(aCol.GetBlue()); + *pOut++ = nAlpha; + } + } + else + { + OSL_ENSURE(m_nRedIndex != -1 && m_nGreenIndex != -1 && m_nBlueIndex != -1, + "Invalid color channel indices"); + + for( std::size_t i=0; i<nLen; i+=nComponentsPerPixel ) + { + // TODO(F3): Convert result to sRGB color space + const double nAlpha( m_nAlphaIndex != -1 ? 1.0 - deviceColor[i+m_nAlphaIndex] : 1.0 ); + *pOut++ = deviceColor[i+m_nRedIndex]; + *pOut++ = deviceColor[i+m_nGreenIndex]; + *pOut++ = deviceColor[i+m_nBlueIndex]; + *pOut++ = nAlpha; + } + } + + return aRes; + } + else + { + // TODO(P3): if we know anything about target + // colorspace, this can be greatly sped up + uno::Sequence<rendering::ARGBColor> aIntermediate( + convertIntegerToARGB(deviceColor)); + return targetColorSpace->convertFromARGB(aIntermediate); + } +} + +uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor, + const uno::Reference< ::rendering::XIntegerBitmapColorSpace >& targetColorSpace ) +{ + if( dynamic_cast<VclCanvasBitmap*>(targetColorSpace.get()) ) + { + // it's us, so simply pass-through the data + return deviceColor; + } + else + { + // TODO(P3): if we know anything about target + // colorspace, this can be greatly sped up + uno::Sequence<rendering::ARGBColor> aIntermediate( + convertIntegerToARGB(deviceColor)); + return targetColorSpace->convertIntegerFromARGB(aIntermediate); + } +} + +uno::Sequence<rendering::RGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) +{ + SolarMutexGuard aGuard; + + const sal_uInt8* pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) ); + const std::size_t nLen( deviceColor.getLength() ); + const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel); + + uno::Sequence< rendering::RGBColor > aRes(nNumColors); + rendering::RGBColor* pOut( aRes.getArray() ); + + BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess(); + ENSURE_OR_THROW(pBmpAcc, + "Unable to get BitmapAccess"); + + if( m_aBmpEx.IsAlpha() ) + { + const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8); + for( std::size_t i=0; i<nLen; i+=nBytesPerPixel ) + { + // if palette, index is guaranteed to be 8 bit + const BitmapColor aCol = + m_bPalette ? + pBmpAcc->GetPaletteColor(*pIn) : + pBmpAcc->GetPixelFromData(pIn,0); + + // TODO(F3): Convert result to sRGB color space + *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()), + toDoubleColor(aCol.GetGreen()), + toDoubleColor(aCol.GetBlue())); + // skips alpha + pIn += nBytesPerPixel; + } + } + else + { + for( sal_Int32 i=0; i<nNumColors; ++i ) + { + const BitmapColor aCol = + m_bPalette ? + pBmpAcc->GetPaletteColor( pBmpAcc->GetPixelFromData( pIn, i ).GetIndex()) : + pBmpAcc->GetPixelFromData(pIn, i); + + // TODO(F3): Convert result to sRGB color space + *pOut++ = rendering::RGBColor(toDoubleColor(aCol.GetRed()), + toDoubleColor(aCol.GetGreen()), + toDoubleColor(aCol.GetBlue())); + } + } + + return aRes; +} + +uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) +{ + SolarMutexGuard aGuard; + + const sal_uInt8* pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) ); + const std::size_t nLen( deviceColor.getLength() ); + const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel); + + uno::Sequence< rendering::ARGBColor > aRes(nNumColors); + rendering::ARGBColor* pOut( aRes.getArray() ); + + BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess(); + ENSURE_OR_THROW(pBmpAcc, + "Unable to get BitmapAccess"); + + if( m_aBmpEx.IsAlpha() ) + { + const tools::Long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 ); + const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8); + for( std::size_t i=0; i<nLen; i+=nBytesPerPixel ) + { + // if palette, index is guaranteed to be 8 bit + const BitmapColor aCol = + m_bPalette ? + pBmpAcc->GetPaletteColor(*pIn) : + pBmpAcc->GetPixelFromData(pIn,0); + + // TODO(F3): Convert result to sRGB color space + *pOut++ = rendering::ARGBColor(1.0 - toDoubleColor(pIn[nNonAlphaBytes]), + toDoubleColor(aCol.GetRed()), + toDoubleColor(aCol.GetGreen()), + toDoubleColor(aCol.GetBlue())); + pIn += nBytesPerPixel; + } + } + else + { + for( sal_Int32 i=0; i<nNumColors; ++i ) + { + const BitmapColor aCol = + m_bPalette ? + pBmpAcc->GetPaletteColor( pBmpAcc->GetPixelFromData( pIn, i ).GetIndex() ) : + pBmpAcc->GetPixelFromData(pIn, i); + + // TODO(F3): Convert result to sRGB color space + *pOut++ = rendering::ARGBColor(1.0, + toDoubleColor(aCol.GetRed()), + toDoubleColor(aCol.GetGreen()), + toDoubleColor(aCol.GetBlue())); + } + } + + return aRes; +} + +uno::Sequence<rendering::ARGBColor> SAL_CALL VclCanvasBitmap::convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) +{ + SolarMutexGuard aGuard; + + const sal_uInt8* pIn( reinterpret_cast<const sal_uInt8*>(deviceColor.getConstArray()) ); + const std::size_t nLen( deviceColor.getLength() ); + const sal_Int32 nNumColors((nLen*8 + m_nBitsPerOutputPixel-1)/m_nBitsPerOutputPixel); + + uno::Sequence< rendering::ARGBColor > aRes(nNumColors); + rendering::ARGBColor* pOut( aRes.getArray() ); + + BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess(); + ENSURE_OR_THROW(pBmpAcc, + "Unable to get BitmapAccess"); + + if( m_aBmpEx.IsAlpha() ) + { + const tools::Long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 ); + const sal_Int32 nBytesPerPixel((m_nBitsPerOutputPixel+7)/8); + for( std::size_t i=0; i<nLen; i+=nBytesPerPixel ) + { + // if palette, index is guaranteed to be 8 bit + const BitmapColor aCol = + m_bPalette ? + pBmpAcc->GetPaletteColor(*pIn) : + pBmpAcc->GetPixelFromData(pIn,0); + + // TODO(F3): Convert result to sRGB color space + const double nAlpha( 1.0 - toDoubleColor(pIn[nNonAlphaBytes]) ); + *pOut++ = rendering::ARGBColor(nAlpha, + nAlpha*toDoubleColor(aCol.GetRed()), + nAlpha*toDoubleColor(aCol.GetGreen()), + nAlpha*toDoubleColor(aCol.GetBlue())); + pIn += nBytesPerPixel; + } + } + else + { + for( sal_Int32 i=0; i<nNumColors; ++i ) + { + const BitmapColor aCol = + m_bPalette ? + pBmpAcc->GetPaletteColor( pBmpAcc->GetPixelFromData( pIn, i ).GetIndex() ) : + pBmpAcc->GetPixelFromData(pIn, i); + + // TODO(F3): Convert result to sRGB color space + *pOut++ = rendering::ARGBColor(1.0, + toDoubleColor(aCol.GetRed()), + toDoubleColor(aCol.GetGreen()), + toDoubleColor(aCol.GetBlue())); + } + } + + return aRes; +} + +uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromRGB( const uno::Sequence<rendering::RGBColor>& rgbColor ) +{ + SolarMutexGuard aGuard; + + const std::size_t nLen( rgbColor.getLength() ); + const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8); + + uno::Sequence< sal_Int8 > aRes(nNumBytes); + sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray()); + BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess(); + + if( m_aBmpEx.IsAlpha() ) + { + const tools::Long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 ); + for( std::size_t i=0; i<nLen; ++i ) + { + const BitmapColor aCol(toByteColor(rgbColor[i].Red), + toByteColor(rgbColor[i].Green), + toByteColor(rgbColor[i].Blue)); + const BitmapColor aCol2 = + m_bPalette ? + BitmapColor( + sal::static_int_cast<sal_uInt8>(pBmpAcc->GetBestPaletteIndex( aCol ))) : + aCol; + + pBmpAcc->SetPixelOnData(pColors,i,aCol2); + pColors += nNonAlphaBytes; + *pColors++ = sal_uInt8(255); + } + } + else + { + for( std::size_t i=0; i<nLen; ++i ) + { + const BitmapColor aCol(toByteColor(rgbColor[i].Red), + toByteColor(rgbColor[i].Green), + toByteColor(rgbColor[i].Blue)); + const BitmapColor aCol2 = + m_bPalette ? + BitmapColor( + sal::static_int_cast<sal_uInt8>(pBmpAcc->GetBestPaletteIndex( aCol ))) : + aCol; + + pBmpAcc->SetPixelOnData(pColors,i,aCol2); + } + } + + return aRes; +} + +uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) +{ + SolarMutexGuard aGuard; + + const std::size_t nLen( rgbColor.getLength() ); + const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8); + + uno::Sequence< sal_Int8 > aRes(nNumBytes); + sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray()); + BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess(); + + if( m_aBmpEx.IsAlpha() ) + { + const tools::Long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 ); + for( std::size_t i=0; i<nLen; ++i ) + { + const BitmapColor aCol(toByteColor(rgbColor[i].Red), + toByteColor(rgbColor[i].Green), + toByteColor(rgbColor[i].Blue)); + const BitmapColor aCol2 = + m_bPalette ? + BitmapColor( + sal::static_int_cast<sal_uInt8>(pBmpAcc->GetBestPaletteIndex( aCol ))) : + aCol; + + pBmpAcc->SetPixelOnData(pColors,i,aCol2); + pColors += nNonAlphaBytes; + *pColors++ = 255 - toByteColor(rgbColor[i].Alpha); + } + } + else + { + for( std::size_t i=0; i<nLen; ++i ) + { + const BitmapColor aCol(toByteColor(rgbColor[i].Red), + toByteColor(rgbColor[i].Green), + toByteColor(rgbColor[i].Blue)); + const BitmapColor aCol2 = + m_bPalette ? + BitmapColor( + sal::static_int_cast<sal_uInt8>(pBmpAcc->GetBestPaletteIndex( aCol ))) : + aCol; + + pBmpAcc->SetPixelOnData(pColors,i,aCol2); + } + } + + return aRes; +} + +uno::Sequence< ::sal_Int8 > SAL_CALL VclCanvasBitmap::convertIntegerFromPARGB( const uno::Sequence<rendering::ARGBColor>& rgbColor ) +{ + SolarMutexGuard aGuard; + + const std::size_t nLen( rgbColor.getLength() ); + const sal_Int32 nNumBytes((nLen*m_nBitsPerOutputPixel+7)/8); + + uno::Sequence< sal_Int8 > aRes(nNumBytes); + sal_uInt8* pColors=reinterpret_cast<sal_uInt8*>(aRes.getArray()); + BitmapScopedReadAccess& pBmpAcc = getBitmapReadAccess(); + + if( m_aBmpEx.IsAlpha() ) + { + const tools::Long nNonAlphaBytes( (m_nBitsPerInputPixel+7)/8 ); + for( std::size_t i=0; i<nLen; ++i ) + { + const double nAlpha( rgbColor[i].Alpha ); + const BitmapColor aCol(toByteColor(rgbColor[i].Red / nAlpha), + toByteColor(rgbColor[i].Green / nAlpha), + toByteColor(rgbColor[i].Blue / nAlpha)); + const BitmapColor aCol2 = + m_bPalette ? + BitmapColor( + sal::static_int_cast<sal_uInt8>(pBmpAcc->GetBestPaletteIndex( aCol ))) : + aCol; + + pBmpAcc->SetPixelOnData(pColors,i,aCol2); + pColors += nNonAlphaBytes; + *pColors++ = 255 - toByteColor(nAlpha); + } + } + else + { + for( std::size_t i=0; i<nLen; ++i ) + { + const BitmapColor aCol(toByteColor(rgbColor[i].Red), + toByteColor(rgbColor[i].Green), + toByteColor(rgbColor[i].Blue)); + const BitmapColor aCol2 = + m_bPalette ? + BitmapColor( + sal::static_int_cast<sal_uInt8>(pBmpAcc->GetBestPaletteIndex( aCol ))) : + aCol; + + pBmpAcc->SetPixelOnData(pColors,i,aCol2); + } + } + + return aRes; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/helper/canvastools.cxx b/vcl/source/helper/canvastools.cxx new file mode 100644 index 0000000000..1e1b2bdd2d --- /dev/null +++ b/vcl/source/helper/canvastools.cxx @@ -0,0 +1,627 @@ +/* -*- 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 <com/sun/star/geometry/RealSize2D.hpp> +#include <com/sun/star/geometry/IntegerSize2D.hpp> +#include <com/sun/star/geometry/IntegerPoint2D.hpp> +#include <com/sun/star/geometry/IntegerRectangle2D.hpp> + +#include <com/sun/star/rendering/ColorSpaceType.hpp> +#include <com/sun/star/rendering/RenderingIntent.hpp> +#include <com/sun/star/rendering/VolatileContentDestroyedException.hpp> +#include <com/sun/star/rendering/XBitmap.hpp> +#include <com/sun/star/rendering/IntegerBitmapLayout.hpp> +#include <com/sun/star/rendering/ColorComponentTag.hpp> + +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/point/b2ipoint.hxx> +#include <basegfx/range/b2irectangle.hxx> + +#include <sal/log.hxx> +#include <tools/helpers.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <vcl/bitmapex.hxx> + +#include <canvasbitmap.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/BitmapWriteAccess.hxx> + +using namespace ::com::sun::star; + +namespace vcl::unotools +{ + uno::Reference< rendering::XBitmap > xBitmapFromBitmapEx(const ::BitmapEx& inputBitmap ) + { + SAL_INFO( "vcl.helper", "vcl::unotools::xBitmapFromBitmapEx()" ); + + return new vcl::unotools::VclCanvasBitmap( inputBitmap ); + } + + namespace + { + bool equalsLayout( const rendering::IntegerBitmapLayout& rLHS, + const rendering::IntegerBitmapLayout& rRHS ) + { + return + rLHS.ScanLineBytes == rRHS.ScanLineBytes && + rLHS.ScanLineStride == rRHS.ScanLineStride && + rLHS.PlaneStride == rRHS.PlaneStride && + rLHS.ColorSpace == rRHS.ColorSpace && + rLHS.Palette == rRHS.Palette && + rLHS.IsMsbFirst == rRHS.IsMsbFirst; + } + bool readBmp( sal_Int32 nWidth, + sal_Int32 nHeight, + const rendering::IntegerBitmapLayout& rLayout, + const uno::Reference< rendering::XIntegerReadOnlyBitmap >& xInputBitmap, + BitmapScopedWriteAccess& rWriteAcc, + BitmapScopedWriteAccess& rAlphaAcc ) + { + rendering::IntegerBitmapLayout aCurrLayout; + geometry::IntegerRectangle2D aRect; + uno::Sequence<sal_Int8> aPixelData; + uno::Sequence<rendering::RGBColor> aRGBColors; + uno::Sequence<rendering::ARGBColor> aARGBColors; + + for( aRect.Y1=0; aRect.Y1<nHeight; ++aRect.Y1 ) + { + aRect.X1 = 0; aRect.X2 = nWidth; aRect.Y2 = aRect.Y1+1; + try + { + aPixelData = xInputBitmap->getData(aCurrLayout,aRect); + } + catch( rendering::VolatileContentDestroyedException& ) + { + // re-read bmp from the start + return false; + } + if( !equalsLayout(aCurrLayout, rLayout) ) + return false; // re-read bmp from the start + + Scanline pScanline = rWriteAcc->GetScanline( aRect.Y1 ); + if( rAlphaAcc.get() ) + { + Scanline pScanlineAlpha = rAlphaAcc->GetScanline( aRect.Y1 ); + // read ARGB color + aARGBColors = rLayout.ColorSpace->convertIntegerToARGB(aPixelData); + + if( rWriteAcc->HasPalette() ) + { + for( sal_Int32 x=0; x<nWidth; ++x ) + { + const rendering::ARGBColor& rColor=aARGBColors[x]; + rWriteAcc->SetPixelOnData( pScanline, x, + BitmapColor(static_cast<sal_uInt8>(rWriteAcc->GetBestPaletteIndex( + BitmapColor( toByteColor(rColor.Red), + toByteColor(rColor.Green), + toByteColor(rColor.Blue))))) ); + rAlphaAcc->SetPixelOnData( pScanlineAlpha, x, + BitmapColor( toByteColor(rColor.Alpha) )); + } + } + else + { + for( sal_Int32 x=0; x<nWidth; ++x ) + { + const rendering::ARGBColor& rColor=aARGBColors[x]; + rWriteAcc->SetPixelOnData( pScanline, x, + BitmapColor( toByteColor(rColor.Red), + toByteColor(rColor.Green), + toByteColor(rColor.Blue) )); + rAlphaAcc->SetPixelOnData( pScanlineAlpha, x, + BitmapColor( toByteColor(rColor.Alpha) )); + } + } + } + else + { + // read RGB color + aRGBColors = rLayout.ColorSpace->convertIntegerToRGB(aPixelData); + if( rWriteAcc->HasPalette() ) + { + for( sal_Int32 x=0; x<nWidth; ++x ) + { + const rendering::RGBColor& rColor=aRGBColors[x]; + rWriteAcc->SetPixelOnData( pScanline, x, + BitmapColor(static_cast<sal_uInt8>(rWriteAcc->GetBestPaletteIndex( + BitmapColor( toByteColor(rColor.Red), + toByteColor(rColor.Green), + toByteColor(rColor.Blue))))) ); + } + } + else + { + for( sal_Int32 x=0; x<nWidth; ++x ) + { + const rendering::RGBColor& rColor=aRGBColors[x]; + rWriteAcc->SetPixelOnData( pScanline, x, + BitmapColor( toByteColor(rColor.Red), + toByteColor(rColor.Green), + toByteColor(rColor.Blue) )); + } + } + } + } + + return true; + } + } + + ::BitmapEx bitmapExFromXBitmap( const uno::Reference< rendering::XIntegerReadOnlyBitmap >& xInputBitmap ) + { + SAL_INFO( "vcl.helper", "vcl::unotools::bitmapExFromXBitmap()" ); + + if( !xInputBitmap.is() ) + return ::BitmapEx(); + + // tunnel directly for known implementation + VclCanvasBitmap* pImplBitmap = dynamic_cast<VclCanvasBitmap*>(xInputBitmap.get()); + if( pImplBitmap ) + return pImplBitmap->getBitmapEx(); + + // retrieve data via UNO interface + + // volatile bitmaps are a bit more complicated to read + // from... + + // loop a few times, until successfully read (for XVolatileBitmap) + for( int i=0; i<10; ++i ) + { + sal_Int32 nDepth=0; + sal_Int32 nAlphaDepth=0; + const rendering::IntegerBitmapLayout aLayout( + xInputBitmap->getMemoryLayout()); + + OSL_ENSURE(aLayout.ColorSpace.is(), + "Cannot convert image without color space!"); + if( !aLayout.ColorSpace.is() ) + return ::BitmapEx(); + + nDepth = aLayout.ColorSpace->getBitsPerPixel(); + + if( xInputBitmap->hasAlpha() ) + { + // determine alpha channel depth + const uno::Sequence<sal_Int8> aTags( + aLayout.ColorSpace->getComponentTags() ); + const sal_Int8* pStart(aTags.getConstArray()); + const std::size_t nLen(aTags.getLength()); + const sal_Int8* pEnd(pStart+nLen); + + const std::ptrdiff_t nAlphaIndex = + std::find(pStart,pEnd, + rendering::ColorComponentTag::ALPHA) - pStart; + + if( nAlphaIndex < sal::static_int_cast<std::ptrdiff_t>(nLen) ) + { + nAlphaDepth = aLayout.ColorSpace->getComponentBitCounts()[nAlphaIndex] > 1 ? 8 : 1; + nDepth -= nAlphaDepth; + } + } + + BitmapPalette aPalette; + if( aLayout.Palette.is() ) + { + uno::Reference< rendering::XColorSpace > xPaletteColorSpace( + aLayout.Palette->getColorSpace()); + ENSURE_OR_THROW(xPaletteColorSpace.is(), + "Palette without color space"); + + const sal_Int32 nEntryCount( aLayout.Palette->getNumberOfEntries() ); + if( nEntryCount <= 256 ) + { + if( nEntryCount <= 2 ) + nDepth = 1; + else + nDepth = 8; + + const sal_uInt16 nPaletteEntries( + sal::static_int_cast<sal_uInt16>( + std::min(sal_Int32(255), nEntryCount))); + + // copy palette entries + aPalette.SetEntryCount(nPaletteEntries); + uno::Reference<rendering::XBitmapPalette> xPalette( aLayout.Palette ); + uno::Reference<rendering::XColorSpace> xPalColorSpace( xPalette->getColorSpace() ); + + uno::Sequence<double> aPaletteEntry; + for( sal_uInt16 j=0; j<nPaletteEntries; ++j ) + { + if( !xPalette->getIndex(aPaletteEntry,j) && + nAlphaDepth == 0 ) + { + nAlphaDepth = 1; + } + uno::Sequence<rendering::RGBColor> aColors=xPalColorSpace->convertToRGB(aPaletteEntry); + ENSURE_OR_THROW(aColors.getLength() == 1, + "Palette returned more or less than one entry"); + const rendering::RGBColor& rColor=aColors[0]; + aPalette[j] = BitmapColor(toByteColor(rColor.Red), + toByteColor(rColor.Green), + toByteColor(rColor.Blue)); + } + } + } + + const ::Size aPixelSize( + sizeFromIntegerSize2D(xInputBitmap->getSize())); + + // normalize bitcount + auto ePixelFormat = + ( nDepth <= 8 ) ? vcl::PixelFormat::N8_BPP : + vcl::PixelFormat::N24_BPP; + auto eAlphaPixelFormat = vcl::PixelFormat::N8_BPP; + + ::Bitmap aBitmap( aPixelSize, + ePixelFormat, + aLayout.Palette.is() ? &aPalette : nullptr ); + ::Bitmap aAlpha; + if( nAlphaDepth ) + aAlpha = Bitmap(aPixelSize, + eAlphaPixelFormat, + &Bitmap::GetGreyPalette( + sal::static_int_cast<sal_uInt16>(1 << nAlphaDepth)) ); + + { // limit scoped access + BitmapScopedWriteAccess pWriteAccess( aBitmap ); + BitmapScopedWriteAccess pAlphaWriteAccess; + if (nAlphaDepth) + pAlphaWriteAccess = aAlpha; + + ENSURE_OR_THROW(pWriteAccess.get() != nullptr, + "Cannot get write access to bitmap"); + + const sal_Int32 nWidth(aPixelSize.Width()); + const sal_Int32 nHeight(aPixelSize.Height()); + + if( !readBmp(nWidth,nHeight,aLayout,xInputBitmap, + pWriteAccess,pAlphaWriteAccess) ) + continue; + } // limit scoped access + + if( nAlphaDepth ) + return ::BitmapEx( aBitmap, + AlphaMask( aAlpha ) ); + else + return ::BitmapEx( aBitmap ); + } + + // failed to read data 10 times - bail out + return ::BitmapEx(); + } + + geometry::RealSize2D size2DFromSize( const Size& rSize ) + { + return geometry::RealSize2D( rSize.Width(), + rSize.Height() ); + } + + Size sizeFromRealSize2D( const geometry::RealSize2D& rSize ) + { + return Size( static_cast<tools::Long>(rSize.Width + .5), + static_cast<tools::Long>(rSize.Height + .5) ); + } + + ::Size sizeFromB2DSize( const basegfx::B2DVector& rVec ) + { + return ::Size( FRound( rVec.getX() ), + FRound( rVec.getY() ) ); + } + + ::Point pointFromB2DPoint( const basegfx::B2DPoint& rPoint ) + { + return pointFromB2IPoint(basegfx::fround(rPoint)); + } + + ::tools::Rectangle rectangleFromB2DRectangle( const basegfx::B2DRange& rRect ) + { + return rectangleFromB2IRectangle(basegfx::fround(rRect)); + } + + Point pointFromB2IPoint( const basegfx::B2IPoint& rPoint ) + { + return ::Point( rPoint.getX(), + rPoint.getY() ); + } + + basegfx::B2IPoint b2IPointFromPoint(Point const& rPoint) + { + return basegfx::B2IPoint(rPoint.X(), rPoint.Y()); + } + + tools::Rectangle rectangleFromB2IRectangle( const basegfx::B2IRange& rRect ) + { + return ::tools::Rectangle( rRect.getMinX(), + rRect.getMinY(), + rRect.getMaxX(), + rRect.getMaxY() ); + } + + basegfx::B2IRectangle b2IRectangleFromRectangle(tools::Rectangle const& rRect) + { + // although B2IRange internally has separate height/width emptiness, it doesn't + // expose any API to let us set them separately, so just do the best we can. + if (rRect.IsWidthEmpty() && rRect.IsHeightEmpty()) + return basegfx::B2IRange( basegfx::B2ITuple( rRect.Left(), rRect.Top() ) ); + return basegfx::B2IRange( rRect.Left(), + rRect.Top(), + rRect.IsWidthEmpty() ? rRect.Left() : rRect.Right(), + rRect.IsHeightEmpty() ? rRect.Top() : rRect.Bottom() ); + } + + basegfx::B2DSize b2DSizeFromSize(const Size& rSize) + { + return basegfx::B2DSize(rSize.Width(), rSize.Height()); + } + + basegfx::B2DVector b2DVectorFromSize(const Size& rSize) + { + return basegfx::B2DVector(rSize.Width(), rSize.Height()); + } + + basegfx::B2DPoint b2DPointFromPoint( const ::Point& rPoint ) + { + return basegfx::B2DPoint( rPoint.X(), + rPoint.Y() ); + } + + basegfx::B2DRange b2DRectangleFromRectangle( const ::tools::Rectangle& rRect ) + { + // although B2DRange internally has separate height/width emptiness, it doesn't + // expose any API to let us set them separately, so just do the best we can. + if (rRect.IsWidthEmpty() && rRect.IsHeightEmpty()) + return basegfx::B2DRange( basegfx::B2DTuple( rRect.Left(), rRect.Top() ) ); + return basegfx::B2DRectangle( rRect.Left(), + rRect.Top(), + rRect.IsWidthEmpty() ? rRect.Left() : rRect.Right(), + rRect.IsHeightEmpty() ? rRect.Top() : rRect.Bottom() ); + } + + geometry::IntegerSize2D integerSize2DFromSize( const Size& rSize ) + { + return geometry::IntegerSize2D( rSize.Width(), + rSize.Height() ); + } + + Size sizeFromIntegerSize2D( const geometry::IntegerSize2D& rSize ) + { + return Size( rSize.Width, + rSize.Height ); + } + + Point pointFromIntegerPoint2D( const geometry::IntegerPoint2D& rPoint ) + { + return Point( rPoint.X, + rPoint.Y ); + } + + tools::Rectangle rectangleFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRectangle ) + { + return tools::Rectangle( rRectangle.X1, rRectangle.Y1, + rRectangle.X2, rRectangle.Y2 ); + } + + namespace + { + class StandardColorSpace : public cppu::WeakImplHelper< css::rendering::XColorSpace > + { + private: + uno::Sequence< sal_Int8 > m_aComponentTags; + + virtual ::sal_Int8 SAL_CALL getType( ) override + { + return rendering::ColorSpaceType::RGB; + } + virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) override + { + return m_aComponentTags; + } + virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) override + { + return rendering::RenderingIntent::PERCEPTUAL; + } + virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) override + { + return uno::Sequence< beans::PropertyValue >(); + } + virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor, + const uno::Reference< rendering::XColorSpace >& targetColorSpace ) override + { + // TODO(P3): if we know anything about target + // colorspace, this can be greatly sped up + uno::Sequence<rendering::ARGBColor> aIntermediate( + convertToARGB(deviceColor)); + return targetColorSpace->convertFromARGB(aIntermediate); + } + virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) override + { + const double* pIn( deviceColor.getConstArray() ); + const std::size_t nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::RGBColor > aRes(nLen/4); + rendering::RGBColor* pOut( aRes.getArray() ); + for( std::size_t i=0; i<nLen; i+=4 ) + { + *pOut++ = rendering::RGBColor(pIn[0],pIn[1],pIn[2]); + pIn += 4; + } + return aRes; + } + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) override + { + const double* pIn( deviceColor.getConstArray() ); + const std::size_t nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::ARGBColor > aRes(nLen/4); + rendering::ARGBColor* pOut( aRes.getArray() ); + for( std::size_t i=0; i<nLen; i+=4 ) + { + *pOut++ = rendering::ARGBColor(pIn[3],pIn[0],pIn[1],pIn[2]); + pIn += 4; + } + return aRes; + } + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) override + { + const double* pIn( deviceColor.getConstArray() ); + const std::size_t nLen( deviceColor.getLength() ); + ENSURE_ARG_OR_THROW2(nLen%4==0, + "number of channels no multiple of 4", + static_cast<rendering::XColorSpace*>(this), 0); + + uno::Sequence< rendering::ARGBColor > aRes(nLen/4); + rendering::ARGBColor* pOut( aRes.getArray() ); + for( std::size_t i=0; i<nLen; i+=4 ) + { + *pOut++ = rendering::ARGBColor(pIn[3],pIn[3]*pIn[0],pIn[3]*pIn[1],pIn[3]*pIn[2]); + pIn += 4; + } + return aRes; + } + virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) override + { + const std::size_t nLen( rgbColor.getLength() ); + + uno::Sequence< double > aRes(nLen*4); + double* pColors=aRes.getArray(); + for( const auto& rIn : rgbColor ) + { + *pColors++ = rIn.Red; + *pColors++ = rIn.Green; + *pColors++ = rIn.Blue; + *pColors++ = 1.0; + } + return aRes; + } + virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override + { + const std::size_t nLen( rgbColor.getLength() ); + + uno::Sequence< double > aRes(nLen*4); + double* pColors=aRes.getArray(); + for( const auto& rIn : rgbColor ) + { + *pColors++ = rIn.Red; + *pColors++ = rIn.Green; + *pColors++ = rIn.Blue; + *pColors++ = rIn.Alpha; + } + return aRes; + } + virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) override + { + const std::size_t nLen( rgbColor.getLength() ); + + uno::Sequence< double > aRes(nLen*4); + double* pColors=aRes.getArray(); + for( const auto& rIn : rgbColor ) + { + *pColors++ = rIn.Red/rIn.Alpha; + *pColors++ = rIn.Green/rIn.Alpha; + *pColors++ = rIn.Blue/rIn.Alpha; + *pColors++ = rIn.Alpha; + } + return aRes; + } + + public: + StandardColorSpace() : m_aComponentTags(4) + { + sal_Int8* pTags = m_aComponentTags.getArray(); + pTags[0] = rendering::ColorComponentTag::RGB_RED; + pTags[1] = rendering::ColorComponentTag::RGB_GREEN; + pTags[2] = rendering::ColorComponentTag::RGB_BLUE; + pTags[3] = rendering::ColorComponentTag::ALPHA; + } + }; + } + + uno::Reference<rendering::XColorSpace> createStandardColorSpace() + { + return new StandardColorSpace(); + } + + uno::Sequence< double > colorToStdColorSpaceSequence( const Color& rColor ) + { + return + { + toDoubleColor(rColor.GetRed()), + toDoubleColor(rColor.GetGreen()), + toDoubleColor(rColor.GetBlue()), + toDoubleColor(rColor.GetAlpha()) + }; + } + + Color stdColorSpaceSequenceToColor( const uno::Sequence< double >& rColor ) + { + ENSURE_ARG_OR_THROW( rColor.getLength() == 4, + "color must have 4 channels" ); + + Color aColor; + + aColor.SetRed ( toByteColor(rColor[0]) ); + aColor.SetGreen( toByteColor(rColor[1]) ); + aColor.SetBlue ( toByteColor(rColor[2]) ); + aColor.SetAlpha( toByteColor(rColor[3]) ); + + return aColor; + } + + uno::Sequence< double > colorToDoubleSequence( + const Color& rColor, + const uno::Reference< rendering::XColorSpace >& xColorSpace ) + { + uno::Sequence<rendering::ARGBColor> aSeq + { + { + toDoubleColor(rColor.GetAlpha()), + toDoubleColor(rColor.GetRed()), + toDoubleColor(rColor.GetGreen()), + toDoubleColor(rColor.GetBlue()) + } + }; + + return xColorSpace->convertFromARGB(aSeq); + } + + Color doubleSequenceToColor( + const uno::Sequence< double >& rColor, + const uno::Reference< rendering::XColorSpace >& xColorSpace ) + { + const rendering::ARGBColor aARGBColor( + xColorSpace->convertToARGB(rColor)[0]); + + return Color( ColorAlpha, toByteColor(aARGBColor.Alpha), + toByteColor(aARGBColor.Red), + toByteColor(aARGBColor.Green), + toByteColor(aARGBColor.Blue) ); + } + +} // namespace canvas + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/helper/commandinfoprovider.cxx b/vcl/source/helper/commandinfoprovider.cxx new file mode 100644 index 0000000000..eb964b34b8 --- /dev/null +++ b/vcl/source/helper/commandinfoprovider.cxx @@ -0,0 +1,477 @@ +/* -*- 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 <vcl/commandinfoprovider.hxx> +#include <vcl/keycod.hxx> +#include <vcl/mnemonic.hxx> +#include <comphelper/string.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/weakref.hxx> + +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/ModuleManager.hpp> +#include <com/sun/star/frame/theUICommandDescription.hpp> +#include <com/sun/star/ui/GlobalAcceleratorConfiguration.hpp> +#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp> +#include <com/sun/star/ui/ImageType.hpp> +#include <com/sun/star/ui/XImageManager.hpp> +#include <com/sun/star/awt/KeyModifier.hpp> + +using namespace css; +using namespace css::uno; + +namespace vcl::CommandInfoProvider { + +static Reference<container::XNameAccess> GetCommandDescription() +{ + static WeakReference<container::XNameAccess> xWeakRef; + css::uno::Reference<container::XNameAccess> xRef(xWeakRef); + + if (!xRef.is()) + { + xRef = frame::theUICommandDescription::get(comphelper::getProcessComponentContext()); + xWeakRef = xRef; + } + + return xRef; +} + +static Reference<ui::XModuleUIConfigurationManagerSupplier> GetModuleConfigurationSupplier() +{ + static WeakReference<ui::XModuleUIConfigurationManagerSupplier> xWeakRef; + css::uno::Reference<ui::XModuleUIConfigurationManagerSupplier> xRef(xWeakRef); + + if (!xRef.is()) + { + xRef = ui::theModuleUIConfigurationManagerSupplier::get(comphelper::getProcessComponentContext()); + xWeakRef = xRef; + } + + return xRef; +} + +static Reference<ui::XAcceleratorConfiguration> GetGlobalAcceleratorConfiguration() +{ + static WeakReference<ui::XAcceleratorConfiguration> xWeakRef; + css::uno::Reference<ui::XAcceleratorConfiguration> xRef(xWeakRef); + + if (!xRef.is()) + { + xRef = ui::GlobalAcceleratorConfiguration::create(comphelper::getProcessComponentContext()); + xWeakRef = xRef; + } + + return xRef; +} + +static Reference<ui::XAcceleratorConfiguration> GetDocumentAcceleratorConfiguration(const Reference<frame::XFrame>& rxFrame) +{ + Reference<frame::XController> xController = rxFrame->getController(); + if (xController.is()) + { + Reference<ui::XUIConfigurationManagerSupplier> xSupplier(xController->getModel(), UNO_QUERY); + if (xSupplier.is()) + { + Reference<ui::XUIConfigurationManager> xConfigurationManager( + xSupplier->getUIConfigurationManager()); + if (xConfigurationManager.is()) + { + return xConfigurationManager->getShortCutManager(); + } + } + } + return nullptr; +} + +static Reference<ui::XAcceleratorConfiguration> GetModuleAcceleratorConfiguration(const Reference<frame::XFrame>& rxFrame) +{ + css::uno::Reference<css::ui::XAcceleratorConfiguration> curModuleAcceleratorConfiguration; + try + { + Reference<ui::XModuleUIConfigurationManagerSupplier> xSupplier(GetModuleConfigurationSupplier()); + Reference<ui::XUIConfigurationManager> xManager ( + xSupplier->getUIConfigurationManager(GetModuleIdentifier(rxFrame))); + if (xManager.is()) + { + curModuleAcceleratorConfiguration = xManager->getShortCutManager(); + } + } + catch (Exception&) + { + } + return curModuleAcceleratorConfiguration; +} + +static vcl::KeyCode AWTKey2VCLKey(const awt::KeyEvent& aAWTKey) +{ + bool bShift = ((aAWTKey.Modifiers & awt::KeyModifier::SHIFT) == awt::KeyModifier::SHIFT ); + bool bMod1 = ((aAWTKey.Modifiers & awt::KeyModifier::MOD1 ) == awt::KeyModifier::MOD1 ); + bool bMod2 = ((aAWTKey.Modifiers & awt::KeyModifier::MOD2 ) == awt::KeyModifier::MOD2 ); + bool bMod3 = ((aAWTKey.Modifiers & awt::KeyModifier::MOD3 ) == awt::KeyModifier::MOD3 ); + sal_uInt16 nKey = static_cast<sal_uInt16>(aAWTKey.KeyCode); + + return vcl::KeyCode(nKey, bShift, bMod1, bMod2, bMod3); +} + +static OUString RetrieveShortcutsFromConfiguration( + const Reference<ui::XAcceleratorConfiguration>& rxConfiguration, + const OUString& rsCommandName) +{ + if (rxConfiguration.is()) + { + try + { + Sequence<OUString> aCommands { rsCommandName }; + + Sequence<Any> aKeyCodes (rxConfiguration->getPreferredKeyEventsForCommandList(aCommands)); + if (aCommands.getLength() == 1) + { + awt::KeyEvent aKeyEvent; + if (aKeyCodes[0] >>= aKeyEvent) + { + return AWTKey2VCLKey(aKeyEvent).GetName(); + } + } + } + catch (css::lang::IllegalArgumentException&) + { + } + } + return OUString(); +} + +static vcl::KeyCode RetrieveKeyCodeShortcutsFromConfiguration( + const Reference<ui::XAcceleratorConfiguration>& rxConfiguration, + const OUString& rsCommandName) +{ + if (rxConfiguration.is()) + { + try + { + Sequence<OUString> aCommands { rsCommandName }; + + Sequence<Any> aKeyCodes (rxConfiguration->getPreferredKeyEventsForCommandList(aCommands)); + if (aCommands.getLength() == 1) + { + awt::KeyEvent aKeyEvent; + if (aKeyCodes[0] >>= aKeyEvent) + { + return AWTKey2VCLKey(aKeyEvent); + } + } + } + catch (css::lang::IllegalArgumentException&) + { + } + } + return vcl::KeyCode(); +} + +static bool ResourceHasKey(const OUString& rsResourceName, const OUString& rsCommandName, const OUString& rsModuleName) +{ + Sequence< OUString > aSequence; + try + { + if (!rsModuleName.isEmpty()) + { + Reference<container::XNameAccess> xNameAccess(GetCommandDescription()); + Reference<container::XNameAccess> xUICommandLabels; + if (xNameAccess->getByName(rsModuleName) >>= xUICommandLabels) + { + xUICommandLabels->getByName(rsResourceName) >>= aSequence; + if (comphelper::findValue(aSequence, rsCommandName) != -1) + return true; + } + } + } + catch (Exception&) + { + } + return false; +} + +Sequence<beans::PropertyValue> GetCommandProperties(const OUString& rsCommandName, const OUString& rsModuleName) +{ + Sequence<beans::PropertyValue> aProperties; + + try + { + if (!rsModuleName.isEmpty()) + { + Reference<container::XNameAccess> xNameAccess(GetCommandDescription()); + Reference<container::XNameAccess> xUICommandLabels; + if ((xNameAccess->getByName(rsModuleName) >>= xUICommandLabels) && xUICommandLabels->hasByName(rsCommandName)) + xUICommandLabels->getByName(rsCommandName) >>= aProperties; + } + } + catch (Exception&) + { + } + + return aProperties; +} + +static OUString GetCommandProperty(const OUString& rsProperty, const Sequence<beans::PropertyValue> &rProperties) +{ + auto pProp = std::find_if(rProperties.begin(), rProperties.end(), + [&rsProperty](const beans::PropertyValue& rProp) { return rProp.Name == rsProperty; }); + if (pProp != rProperties.end()) + { + OUString sLabel; + pProp->Value >>= sLabel; + return sLabel; + } + return OUString(); +} + +OUString GetLabelForCommand(const css::uno::Sequence<css::beans::PropertyValue>& rProperties) +{ + return GetCommandProperty("Name", rProperties); +} + +OUString GetMenuLabelForCommand(const css::uno::Sequence<css::beans::PropertyValue>& rProperties) +{ + // Here we want to use "Label", not "Name". "Name" is a stripped-down version of "Label" without accelerators + // and ellipsis. In the menu, we want to have those accelerators and ellipsis. + return GetCommandProperty("Label", rProperties); +} + +OUString GetPopupLabelForCommand(const css::uno::Sequence<css::beans::PropertyValue>& rProperties) +{ + OUString sPopupLabel(GetCommandProperty("PopupLabel", rProperties)); + if (!sPopupLabel.isEmpty()) + return sPopupLabel; + return GetCommandProperty("Label", rProperties); +} + +OUString GetTooltipLabelForCommand(const css::uno::Sequence<css::beans::PropertyValue>& rProperties) +{ + OUString sLabel(GetCommandProperty("TooltipLabel", rProperties)); + if (!sLabel.isEmpty()) + return sLabel; + return GetCommandProperty("Label", rProperties); +} + +OUString GetTooltipForCommand( + const OUString& rsCommandName, + const css::uno::Sequence<css::beans::PropertyValue>& rProperties, + const Reference<frame::XFrame>& rxFrame) +{ + OUString sLabel(GetCommandProperty("TooltipLabel", rProperties)); + if (sLabel.isEmpty()) { + sLabel = GetPopupLabelForCommand(rProperties); + // Remove '...' at the end and mnemonics (we don't want those in tooltips) + sLabel = comphelper::string::stripEnd(sLabel, '.'); + sLabel = MnemonicGenerator::EraseAllMnemonicChars(sLabel); + } + + // Command can be just an alias to another command, + // so need to get the shortcut of the "real" command. + const OUString sRealCommand(GetRealCommandForCommand(rProperties)); + const OUString sShortCut(GetCommandShortcut(!sRealCommand.isEmpty() ? sRealCommand : rsCommandName, rxFrame)); + if (!sShortCut.isEmpty()) + return sLabel + " (" + sShortCut + ")"; + return sLabel; +} + +OUString GetCommandShortcut (const OUString& rsCommandName, + const Reference<frame::XFrame>& rxFrame) +{ + + OUString sShortcut; + + sShortcut = RetrieveShortcutsFromConfiguration(GetDocumentAcceleratorConfiguration(rxFrame), rsCommandName); + if (sShortcut.getLength() > 0) + return sShortcut; + + sShortcut = RetrieveShortcutsFromConfiguration(GetModuleAcceleratorConfiguration(rxFrame), rsCommandName); + if (sShortcut.getLength() > 0) + return sShortcut; + + sShortcut = RetrieveShortcutsFromConfiguration(GetGlobalAcceleratorConfiguration(), rsCommandName); + if (sShortcut.getLength() > 0) + return sShortcut; + + return OUString(); +} + +vcl::KeyCode GetCommandKeyCodeShortcut (const OUString& rsCommandName, const Reference<frame::XFrame>& rxFrame) +{ + vcl::KeyCode aKeyCodeShortcut; + + aKeyCodeShortcut = RetrieveKeyCodeShortcutsFromConfiguration(GetDocumentAcceleratorConfiguration(rxFrame), rsCommandName); + if (aKeyCodeShortcut.GetCode()) + return aKeyCodeShortcut; + + aKeyCodeShortcut = RetrieveKeyCodeShortcutsFromConfiguration(GetModuleAcceleratorConfiguration(rxFrame), rsCommandName); + if (aKeyCodeShortcut.GetCode()) + return aKeyCodeShortcut; + + aKeyCodeShortcut = RetrieveKeyCodeShortcutsFromConfiguration(GetGlobalAcceleratorConfiguration(), rsCommandName); + if (aKeyCodeShortcut.GetCode()) + return aKeyCodeShortcut; + + return vcl::KeyCode(); +} + +OUString GetRealCommandForCommand(const css::uno::Sequence<css::beans::PropertyValue>& rProperties) +{ + return GetCommandProperty("TargetURL", rProperties); +} + +Reference<graphic::XGraphic> GetXGraphicForCommand(const OUString& rsCommandName, + const Reference<frame::XFrame>& rxFrame, + vcl::ImageType eImageType) +{ + if (rsCommandName.isEmpty()) + return nullptr; + + sal_Int16 nImageType(ui::ImageType::COLOR_NORMAL | ui::ImageType::SIZE_DEFAULT); + + if (eImageType == vcl::ImageType::Size26) + nImageType |= ui::ImageType::SIZE_LARGE; + else if (eImageType == vcl::ImageType::Size32) + nImageType |= ui::ImageType::SIZE_32; + + try + { + Reference<frame::XController> xController(rxFrame->getController(), UNO_SET_THROW); + Reference<ui::XUIConfigurationManagerSupplier> xSupplier(xController->getModel(), UNO_QUERY); + if (xSupplier.is()) + { + Reference<ui::XUIConfigurationManager> xDocUICfgMgr(xSupplier->getUIConfigurationManager()); + Reference<ui::XImageManager> xDocImgMgr(xDocUICfgMgr->getImageManager(), UNO_QUERY); + + Sequence<OUString> aImageCmdSeq { rsCommandName }; + + Sequence<Reference<graphic::XGraphic>> aGraphicSeq = xDocImgMgr->getImages(nImageType, aImageCmdSeq); + Reference<graphic::XGraphic> xGraphic = aGraphicSeq[0]; + if (xGraphic.is()) + return xGraphic; + } + } + catch (Exception&) + { + } + + try + { + Reference<ui::XModuleUIConfigurationManagerSupplier> xModuleCfgMgrSupplier(GetModuleConfigurationSupplier()); + Reference<ui::XUIConfigurationManager> xUICfgMgr(xModuleCfgMgrSupplier->getUIConfigurationManager(GetModuleIdentifier(rxFrame))); + Reference<ui::XImageManager> xModuleImageManager(xUICfgMgr->getImageManager(), UNO_QUERY); + + Sequence<OUString> aImageCmdSeq { rsCommandName }; + + Sequence<Reference<graphic::XGraphic>> aGraphicSeq = xModuleImageManager->getImages(nImageType, aImageCmdSeq); + Reference<graphic::XGraphic> xGraphic(aGraphicSeq[0]); + + return xGraphic; + } + catch (Exception&) + { + } + + return nullptr; +} + +Image GetImageForCommand(const OUString& rsCommandName, + const Reference<frame::XFrame>& rxFrame, + vcl::ImageType eImageType) +{ + return Image(GetXGraphicForCommand(rsCommandName, rxFrame, eImageType)); +} + +sal_Int32 GetPropertiesForCommand ( + const OUString& rsCommandName, + const OUString& rsModuleName) +{ + sal_Int32 nValue = 0; + const Sequence<beans::PropertyValue> aProperties (GetCommandProperties(rsCommandName, rsModuleName)); + + auto pProp = std::find_if(aProperties.begin(), aProperties.end(), + [](const beans::PropertyValue& rProp) { return rProp.Name == "Properties"; }); + if (pProp != aProperties.end()) + pProp->Value >>= nValue; + + return nValue; +} + +bool IsRotated(const OUString& rsCommandName, const OUString& rsModuleName) +{ + return ResourceHasKey("private:resource/image/commandrotateimagelist", rsCommandName, rsModuleName); +} + +bool IsMirrored(const OUString& rsCommandName, const OUString& rsModuleName) +{ + return ResourceHasKey("private:resource/image/commandmirrorimagelist", rsCommandName, rsModuleName); +} + +bool IsExperimental(const OUString& rsCommandName, const OUString& rModuleName) +{ + Sequence<beans::PropertyValue> aProperties; + try + { + if( rModuleName.getLength() > 0) + { + Reference<container::XNameAccess> xNameAccess(GetCommandDescription()); + Reference<container::XNameAccess> xUICommandLabels; + if (xNameAccess->getByName( rModuleName ) >>= xUICommandLabels ) + xUICommandLabels->getByName(rsCommandName) >>= aProperties; + + auto pProp = std::find_if(std::cbegin(aProperties), std::cend(aProperties), + [](const beans::PropertyValue& rProp) { return rProp.Name == "IsExperimental"; }); + if (pProp != std::cend(aProperties)) + { + bool bValue; + return (pProp->Value >>= bValue) && bValue; + } + } + } + catch (Exception&) + { + } + return false; +} + +OUString GetModuleIdentifier(const Reference<frame::XFrame>& rxFrame) +{ + static WeakReference<frame::XModuleManager2> xWeakRef; + css::uno::Reference<frame::XModuleManager2> xRef(xWeakRef); + + if (!xRef.is()) + { + xRef = frame::ModuleManager::create(comphelper::getProcessComponentContext()); + xWeakRef = xRef; + } + + try + { + return xRef->identify(rxFrame); + } + catch (const Exception&) + {} + + return OUString(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/helper/displayconnectiondispatch.cxx b/vcl/source/helper/displayconnectiondispatch.cxx new file mode 100644 index 0000000000..b06067b9d7 --- /dev/null +++ b/vcl/source/helper/displayconnectiondispatch.cxx @@ -0,0 +1,111 @@ +/* -*- 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 <vcl/svapp.hxx> +#include <tools/debug.hxx> + +#include <displayconnectiondispatch.hxx> +#include <svdata.hxx> +#include <salinst.hxx> + +using namespace osl; +using namespace vcl; +using namespace com::sun::star::uno; +using namespace com::sun::star::awt; + +DisplayConnectionDispatch::DisplayConnectionDispatch() +{ + m_ConnectionIdentifier = ImplGetSVData()->mpDefInst->GetConnectionIdentifier(); +} + +DisplayConnectionDispatch::~DisplayConnectionDispatch() +{} + +void DisplayConnectionDispatch::start() +{ + DBG_TESTSOLARMUTEX(); + ImplSVData* pSVData = ImplGetSVData(); + pSVData->mpDefInst->SetEventCallback( this ); +} + +void DisplayConnectionDispatch::terminate() +{ + DBG_TESTSOLARMUTEX(); + ImplSVData* pSVData = ImplGetSVData(); + + if( pSVData ) + { + pSVData->mpDefInst->SetEventCallback( nullptr ); + } + + SolarMutexReleaser aRel; + + std::scoped_lock aGuard( m_aMutex ); + Any aEvent; + std::vector< css::uno::Reference< XEventHandler > > aLocalList( m_aHandlers ); + for (auto const& elem : aLocalList) + elem->handleEvent( aEvent ); +} + +void SAL_CALL DisplayConnectionDispatch::addEventHandler( const Any& /*window*/, const css::uno::Reference< XEventHandler >& handler, sal_Int32 /*eventMask*/ ) +{ + std::scoped_lock aGuard( m_aMutex ); + + m_aHandlers.push_back( handler ); +} + +void SAL_CALL DisplayConnectionDispatch::removeEventHandler( const Any& /*window*/, const css::uno::Reference< XEventHandler >& handler ) +{ + std::scoped_lock aGuard( m_aMutex ); + + std::erase(m_aHandlers, handler); +} + +void SAL_CALL DisplayConnectionDispatch::addErrorHandler( const css::uno::Reference< XEventHandler >& ) +{ +} + +void SAL_CALL DisplayConnectionDispatch::removeErrorHandler( const css::uno::Reference< XEventHandler >& ) +{ +} + +Any SAL_CALL DisplayConnectionDispatch::getIdentifier() +{ + return Any(m_ConnectionIdentifier); +} + +bool DisplayConnectionDispatch::dispatchEvent( void const * pData, int nBytes ) +{ + SolarMutexReleaser aRel; + + Sequence< sal_Int8 > aSeq( static_cast<const sal_Int8*>(pData), nBytes ); + Any aEvent; + aEvent <<= aSeq; + ::std::vector< css::uno::Reference< XEventHandler > > handlers; + { + std::scoped_lock aGuard( m_aMutex ); + handlers = m_aHandlers; + } + for (auto const& handle : handlers) + if( handle->handleEvent( aEvent ) ) + return true; + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/helper/driverblocklist.cxx b/vcl/source/helper/driverblocklist.cxx new file mode 100644 index 0000000000..e17b45e7a9 --- /dev/null +++ b/vcl/source/helper/driverblocklist.cxx @@ -0,0 +1,769 @@ +/* -*- 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/. + */ + +#include <driverblocklist.hxx> + +#include <algorithm> +#include <string_view> + +#include <sal/log.hxx> +#include <utility> + +#ifdef _WIN32 +#if !defined WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#endif + +namespace DriverBlocklist +{ +static OperatingSystem getOperatingSystem(std::string_view rString) +{ + if (rString == "all") + return DRIVER_OS_ALL; + else if (rString == "7") + return DRIVER_OS_WINDOWS_7; + else if (rString == "8") + return DRIVER_OS_WINDOWS_8; + else if (rString == "8_1") + return DRIVER_OS_WINDOWS_8_1; + else if (rString == "10") + return DRIVER_OS_WINDOWS_10; + else if (rString == "windows") + return DRIVER_OS_WINDOWS_ALL; + else if (rString == "linux") + return DRIVER_OS_LINUX; + else if (rString == "osx_10_5") + return DRIVER_OS_OSX_10_5; + else if (rString == "osx_10_6") + return DRIVER_OS_OSX_10_6; + else if (rString == "osx_10_7") + return DRIVER_OS_OSX_10_7; + else if (rString == "osx_10_8") + return DRIVER_OS_OSX_10_8; + else if (rString == "osx") + return DRIVER_OS_OSX_ALL; + else if (rString == "android") + return DRIVER_OS_ANDROID; + return DRIVER_OS_UNKNOWN; +} + +static VersionComparisonOp getComparison(std::string_view rString) +{ + if (rString == "less") + { + return DRIVER_LESS_THAN; + } + else if (rString == "less_equal") + { + return DRIVER_LESS_THAN_OR_EQUAL; + } + else if (rString == "greater") + { + return DRIVER_GREATER_THAN; + } + else if (rString == "greater_equal") + { + return DRIVER_GREATER_THAN_OR_EQUAL; + } + else if (rString == "equal") + { + return DRIVER_EQUAL; + } + else if (rString == "not_equal") + { + return DRIVER_NOT_EQUAL; + } + else if (rString == "between_exclusive") + { + return DRIVER_BETWEEN_EXCLUSIVE; + } + else if (rString == "between_inclusive") + { + return DRIVER_BETWEEN_INCLUSIVE; + } + else if (rString == "between_inclusive_start") + { + return DRIVER_BETWEEN_INCLUSIVE_START; + } + + throw InvalidFileException(); +} + +static OUString GetVendorId(std::string_view rString) +{ + if (rString == "all") + { + return ""; + } + else if (rString == "intel") + { + return "0x8086"; + } + else if (rString == "nvidia") + { + return "0x10de"; + } + else if (rString == "amd") + { + return "0x1002"; + } + else if (rString == "microsoft") + { + return "0x1414"; + } + else + { + // Allow having simply the hex number as such there, too. + return OStringToOUString(rString, RTL_TEXTENCODING_UTF8); + } +} + +OUString GetVendorId(DeviceVendor id) +{ + assert(id >= 0 && id < DeviceVendorMax); + + switch (id) + { + case VendorAll: + return ""; + case VendorIntel: + return "0x8086"; + case VendorNVIDIA: + return "0x10de"; + case VendorAMD: + return "0x1002"; + case VendorMicrosoft: + return "0x1414"; + } + abort(); +} + +DeviceVendor GetVendorFromId(uint32_t id) +{ + switch (id) + { + case 0x8086: + return VendorIntel; + case 0x10de: + return VendorNVIDIA; + case 0x1002: + return VendorAMD; + case 0x1414: + return VendorMicrosoft; + default: + return VendorAll; + } +} + +std::string_view GetVendorNameFromId(uint32_t id) +{ + switch (id) + { + case 0x8086: + return "Intel"; + case 0x10de: + return "Nvidia"; + case 0x1002: + return "AMD"; + case 0x1414: + return "Microsoft"; + default: + return "?"; + } +} + +Parser::Parser(OUString aURL, std::vector<DriverInfo>& rDriverList, VersionType versionType) + : meBlockType(BlockType::UNKNOWN) + , mrDriverList(rDriverList) + , maURL(std::move(aURL)) + , mVersionType(versionType) +{ +} + +bool Parser::parse() +{ + try + { + xmlreader::XmlReader aReader(maURL); + handleContent(aReader); + } + catch (...) + { + mrDriverList.clear(); + return false; + } + return true; +} + +// This allows us to pad driver version 'substrings' with 0s, this +// effectively allows us to treat the version numbers as 'decimals'. This is +// a little strange but this method seems to do the right thing for all +// different vendor's driver strings. i.e. .98 will become 9800, which is +// larger than .978 which would become 9780. +static void PadDriverDecimal(char* aString) +{ + for (int i = 0; i < 4; i++) + { + if (!aString[i]) + { + for (int c = i; c < 4; c++) + { + aString[c] = '0'; + } + break; + } + } + aString[4] = 0; +} + +// All destination string storage needs to have at least 5 bytes available. +static bool SplitDriverVersion(const char* aSource, char* aAStr, char* aBStr, char* aCStr, + char* aDStr, VersionType versionType) +{ + // sscanf doesn't do what we want here to we parse this manually. + int len = strlen(aSource); + char* dest[4] = { aAStr, aBStr, aCStr, aDStr }; + unsigned destIdx = 0; + unsigned destPos = 0; + + for (int i = 0; i < len; i++) + { + if (destIdx >= SAL_N_ELEMENTS(dest)) + { + // Invalid format found. Ensure we don't access dest beyond bounds. + return false; + } + + if (aSource[i] == '.') + { + dest[destIdx++][destPos] = 0; + destPos = 0; + continue; + } + + if (destPos > 3) + { + // Ignore more than 4 chars. Ensure we never access dest[destIdx] + // beyond its bounds. + continue; + } + + dest[destIdx][destPos++] = aSource[i]; + } + + // Add last terminator. + dest[destIdx][destPos] = 0; + + // Vulkan version numbers have only 3 fields. + if (versionType == VersionType::Vulkan && destIdx == SAL_N_ELEMENTS(dest) - 2) + dest[++destIdx][0] = '\0'; + if (destIdx != SAL_N_ELEMENTS(dest) - 1) + { + return false; + } + return true; +} + +static bool ParseDriverVersion(std::u16string_view aVersion, uint64_t& rNumericVersion, + VersionType versionType) +{ + rNumericVersion = 0; + + int a, b, c, d; + char aStr[8], bStr[8], cStr[8], dStr[8]; + /* honestly, why do I even bother */ + OString aOVersion = OUStringToOString(aVersion, RTL_TEXTENCODING_UTF8); + if (!SplitDriverVersion(aOVersion.getStr(), aStr, bStr, cStr, dStr, versionType)) + return false; + + if (versionType == VersionType::OpenGL) + { + PadDriverDecimal(bStr); + PadDriverDecimal(cStr); + PadDriverDecimal(dStr); + } + + a = atoi(aStr); + b = atoi(bStr); + c = atoi(cStr); + d = atoi(dStr); + + if (versionType == VersionType::Vulkan) + assert(d == 0); + + if (a < 0 || a > 0xffff) + return false; + if (b < 0 || b > 0xffff) + return false; + if (c < 0 || c > 0xffff) + return false; + if (d < 0 || d > 0xffff) + return false; + + rNumericVersion = GFX_DRIVER_VERSION(a, b, c, d); + return true; +} + +uint64_t Parser::getVersion(std::string_view rString) +{ + OUString aString = OStringToOUString(rString, RTL_TEXTENCODING_UTF8); + uint64_t nVersion; + bool bResult = ParseDriverVersion(aString, nVersion, mVersionType); + + if (!bResult) + { + throw InvalidFileException(); + } + + return nVersion; +} + +void Parser::handleDevices(DriverInfo& rDriver, xmlreader::XmlReader& rReader) +{ + int nLevel = 1; + bool bInMsg = false; + + while (true) + { + xmlreader::Span name; + int nsId; + + xmlreader::XmlReader::Result res + = rReader.nextItem(xmlreader::XmlReader::Text::Normalized, &name, &nsId); + + if (res == xmlreader::XmlReader::Result::Begin) + { + ++nLevel; + if (nLevel > 2) + throw InvalidFileException(); + + if (name == "msg") + { + bInMsg = true; + } + else if (name == "device") + { + int nsIdDeveice; + while (rReader.nextAttribute(&nsIdDeveice, &name)) + { + if (name == "id") + { + name = rReader.getAttributeValue(false); + OString aDeviceId(name.begin, name.length); + rDriver.maDevices.push_back( + OStringToOUString(aDeviceId, RTL_TEXTENCODING_UTF8)); + } + } + } + else + throw InvalidFileException(); + } + else if (res == xmlreader::XmlReader::Result::End) + { + --nLevel; + bInMsg = false; + if (!nLevel) + break; + } + else if (res == xmlreader::XmlReader::Result::Text) + { + if (bInMsg) + { + OString sMsg(name.begin, name.length); + rDriver.maMsg = OStringToOUString(sMsg, RTL_TEXTENCODING_UTF8); + } + } + } +} + +void Parser::handleEntry(DriverInfo& rDriver, xmlreader::XmlReader& rReader) +{ + if (meBlockType == BlockType::ALLOWLIST) + { + rDriver.mbAllowlisted = true; + } + else if (meBlockType == BlockType::DENYLIST) + { + rDriver.mbAllowlisted = false; + } + else if (meBlockType == BlockType::UNKNOWN) + { + throw InvalidFileException(); + } + + xmlreader::Span name; + int nsId; + + while (rReader.nextAttribute(&nsId, &name)) + { + if (name == "os") + { + name = rReader.getAttributeValue(false); + OString sOS(name.begin, name.length); + rDriver.meOperatingSystem = getOperatingSystem(sOS); + } + else if (name == "vendor") + { + name = rReader.getAttributeValue(false); + OString sVendor(name.begin, name.length); + rDriver.maAdapterVendor = GetVendorId(sVendor); + } + else if (name == "compare") + { + name = rReader.getAttributeValue(false); + OString sCompare(name.begin, name.length); + rDriver.meComparisonOp = getComparison(sCompare); + } + else if (name == "version") + { + name = rReader.getAttributeValue(false); + OString sVersion(name.begin, name.length); + rDriver.mnDriverVersion = getVersion(sVersion); + } + else if (name == "minVersion") + { + name = rReader.getAttributeValue(false); + OString sMinVersion(name.begin, name.length); + rDriver.mnDriverVersion = getVersion(sMinVersion); + } + else if (name == "maxVersion") + { + name = rReader.getAttributeValue(false); + OString sMaxVersion(name.begin, name.length); + rDriver.mnDriverVersionMax = getVersion(sMaxVersion); + } + else + { + OString aAttrName(name.begin, name.length); + SAL_WARN("vcl.driver", "unsupported attribute: " << aAttrName); + } + } + + handleDevices(rDriver, rReader); +} + +void Parser::handleList(xmlreader::XmlReader& rReader) +{ + xmlreader::Span name; + int nsId; + + while (true) + { + xmlreader::XmlReader::Result res + = rReader.nextItem(xmlreader::XmlReader::Text::NONE, &name, &nsId); + + if (res == xmlreader::XmlReader::Result::Begin) + { + if (name == "entry") + { + DriverInfo aDriver; + handleEntry(aDriver, rReader); + mrDriverList.push_back(aDriver); + } + else if (name == "entryRange") + { + DriverInfo aDriver; + handleEntry(aDriver, rReader); + mrDriverList.push_back(aDriver); + } + else + { + throw InvalidFileException(); + } + } + else if (res == xmlreader::XmlReader::Result::End) + { + break; + } + } +} + +void Parser::handleContent(xmlreader::XmlReader& rReader) +{ + while (true) + { + xmlreader::Span name; + int nsId; + + xmlreader::XmlReader::Result res + = rReader.nextItem(xmlreader::XmlReader::Text::NONE, &name, &nsId); + + if (res == xmlreader::XmlReader::Result::Begin) + { + if (name == "allowlist") + { + meBlockType = BlockType::ALLOWLIST; + handleList(rReader); + } + else if (name == "denylist") + { + meBlockType = BlockType::DENYLIST; + handleList(rReader); + } + else if (name == "root") + { + } + else + { + throw InvalidFileException(); + } + } + else if (res == xmlreader::XmlReader::Result::End) + { + if (name == "allowlist" || name == "denylist") + { + meBlockType = BlockType::UNKNOWN; + } + } + else if (res == xmlreader::XmlReader::Result::Done) + { + break; + } + } +} + +static OperatingSystem getOperatingSystem() +{ +#ifdef _WIN32 + // OS version in 16.16 major/minor form + // based on http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx + switch (DriverBlocklist::GetWindowsVersion()) + { + case 0x00060001: + return DRIVER_OS_WINDOWS_7; + case 0x00060002: + return DRIVER_OS_WINDOWS_8; + case 0x00060003: + return DRIVER_OS_WINDOWS_8_1; + case 0x000A0000: // Major 10 Minor 0 + return DRIVER_OS_WINDOWS_10; + default: + return DRIVER_OS_UNKNOWN; + } +#elif defined LINUX + return DRIVER_OS_LINUX; +#else + return DRIVER_OS_UNKNOWN; +#endif +} + +namespace +{ +struct compareIgnoreAsciiCase +{ + explicit compareIgnoreAsciiCase(OUString aString) + : maString(std::move(aString)) + { + } + + bool operator()(std::u16string_view rCompare) + { + return maString.equalsIgnoreAsciiCase(rCompare); + } + +private: + OUString maString; +}; +} + +const uint64_t allDriverVersions = ~(uint64_t(0)); + +DriverInfo::DriverInfo() + : meOperatingSystem(DRIVER_OS_UNKNOWN) + , maAdapterVendor(GetVendorId(VendorAll)) + , mbAllowlisted(false) + , meComparisonOp(DRIVER_COMPARISON_IGNORED) + , mnDriverVersion(0) + , mnDriverVersionMax(0) +{ +} + +DriverInfo::DriverInfo(OperatingSystem os, OUString vendor, VersionComparisonOp op, + uint64_t driverVersion, bool bAllowlisted, + const char* suggestedVersion /* = nullptr */) + : meOperatingSystem(os) + , maAdapterVendor(std::move(vendor)) + , mbAllowlisted(bAllowlisted) + , meComparisonOp(op) + , mnDriverVersion(driverVersion) + , mnDriverVersionMax(0) +{ + if (suggestedVersion) + maSuggestedVersion + = OStringToOUString(std::string_view(suggestedVersion), RTL_TEXTENCODING_UTF8); +} + +bool FindBlocklistedDeviceInList(std::vector<DriverInfo>& aDeviceInfos, VersionType versionType, + std::u16string_view sDriverVersion, + std::u16string_view sAdapterVendorID, + OUString const& sAdapterDeviceID, OperatingSystem system, + const OUString& blocklistURL) +{ + uint64_t driverVersion; + ParseDriverVersion(sDriverVersion, driverVersion, versionType); + + bool match = false; + for (std::vector<DriverInfo>::size_type i = 0; i < aDeviceInfos.size(); i++) + { + bool osMatch = false; + if (aDeviceInfos[i].meOperatingSystem == DRIVER_OS_ALL) + osMatch = true; + else if (aDeviceInfos[i].meOperatingSystem == system) + osMatch = true; + else if (aDeviceInfos[i].meOperatingSystem == DRIVER_OS_WINDOWS_ALL + && system >= DRIVER_OS_WINDOWS_FIRST && system <= DRIVER_OS_WINDOWS_LAST) + osMatch = true; + else if (aDeviceInfos[i].meOperatingSystem == DRIVER_OS_OSX_ALL + && system >= DRIVER_OS_OSX_FIRST && system <= DRIVER_OS_OSX_LAST) + osMatch = true; + if (!osMatch) + { + continue; + } + + if (!aDeviceInfos[i].maAdapterVendor.equalsIgnoreAsciiCase(GetVendorId(VendorAll)) + && !aDeviceInfos[i].maAdapterVendor.equalsIgnoreAsciiCase(sAdapterVendorID)) + { + continue; + } + + if (std::none_of(aDeviceInfos[i].maDevices.begin(), aDeviceInfos[i].maDevices.end(), + compareIgnoreAsciiCase("all")) + && std::none_of(aDeviceInfos[i].maDevices.begin(), aDeviceInfos[i].maDevices.end(), + compareIgnoreAsciiCase(sAdapterDeviceID))) + { + continue; + } + + switch (aDeviceInfos[i].meComparisonOp) + { + case DRIVER_LESS_THAN: + match = driverVersion < aDeviceInfos[i].mnDriverVersion; + break; + case DRIVER_LESS_THAN_OR_EQUAL: + match = driverVersion <= aDeviceInfos[i].mnDriverVersion; + break; + case DRIVER_GREATER_THAN: + match = driverVersion > aDeviceInfos[i].mnDriverVersion; + break; + case DRIVER_GREATER_THAN_OR_EQUAL: + match = driverVersion >= aDeviceInfos[i].mnDriverVersion; + break; + case DRIVER_EQUAL: + match = driverVersion == aDeviceInfos[i].mnDriverVersion; + break; + case DRIVER_NOT_EQUAL: + match = driverVersion != aDeviceInfos[i].mnDriverVersion; + break; + case DRIVER_BETWEEN_EXCLUSIVE: + match = driverVersion > aDeviceInfos[i].mnDriverVersion + && driverVersion < aDeviceInfos[i].mnDriverVersionMax; + break; + case DRIVER_BETWEEN_INCLUSIVE: + match = driverVersion >= aDeviceInfos[i].mnDriverVersion + && driverVersion <= aDeviceInfos[i].mnDriverVersionMax; + break; + case DRIVER_BETWEEN_INCLUSIVE_START: + match = driverVersion >= aDeviceInfos[i].mnDriverVersion + && driverVersion < aDeviceInfos[i].mnDriverVersionMax; + break; + case DRIVER_COMPARISON_IGNORED: + // We don't have a comparison op, so we match everything. + match = true; + break; + default: + SAL_WARN("vcl.driver", "Bogus op in " << blocklistURL); + break; + } + + if (match || aDeviceInfos[i].mnDriverVersion == allDriverVersions) + { + // white listed drivers + if (aDeviceInfos[i].mbAllowlisted) + { + SAL_INFO("vcl.driver", "allowlisted driver"); + return false; + } + + match = true; + if (!aDeviceInfos[i].maSuggestedVersion.isEmpty()) + { + SAL_WARN("vcl.driver", "use : " << aDeviceInfos[i].maSuggestedVersion); + } + break; + } + } + + SAL_INFO("vcl.driver", (match ? "denylisted" : "not denylisted") << " in " << blocklistURL); + return match; +} + +bool IsDeviceBlocked(const OUString& blocklistURL, VersionType versionType, + std::u16string_view driverVersion, std::u16string_view vendorId, + const OUString& deviceId) +{ + std::vector<DriverInfo> driverList; + Parser parser(blocklistURL, driverList, versionType); + if (!parser.parse()) + { + SAL_WARN("vcl.driver", "error parsing denylist " << blocklistURL); + return false; + } + return FindBlocklistedDeviceInList(driverList, versionType, driverVersion, vendorId, deviceId, + getOperatingSystem(), blocklistURL); +} + +#ifdef _WIN32 +int32_t GetWindowsVersion() +{ + static int32_t winVersion = []() { + // GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API are + // subject to manifest-based behavior since Windows 8.1, so give wrong results. + // Another approach would be to use NetWkstaGetInfo, but that has some small + // reported delays (some milliseconds), and might get slower in domains with + // poor network connections. + // So go with a solution described at https://msdn.microsoft.com/en-us/library/ms724429 + HINSTANCE hLibrary = LoadLibraryW(L"kernel32.dll"); + if (hLibrary != nullptr) + { + wchar_t szPath[MAX_PATH]; + DWORD dwCount = GetModuleFileNameW(hLibrary, szPath, SAL_N_ELEMENTS(szPath)); + FreeLibrary(hLibrary); + if (dwCount != 0 && dwCount < SAL_N_ELEMENTS(szPath)) + { + dwCount = GetFileVersionInfoSizeW(szPath, nullptr); + if (dwCount != 0) + { + std::unique_ptr<char[]> ver(new char[dwCount]); + if (GetFileVersionInfoW(szPath, 0, dwCount, ver.get()) != FALSE) + { + void* pBlock = nullptr; + UINT dwBlockSz = 0; + if (VerQueryValueW(ver.get(), L"\\", &pBlock, &dwBlockSz) != FALSE + && dwBlockSz >= sizeof(VS_FIXEDFILEINFO)) + { + VS_FIXEDFILEINFO* vinfo = static_cast<VS_FIXEDFILEINFO*>(pBlock); + return int32_t(vinfo->dwProductVersionMS); + } + } + } + } + } + return 0; + }(); + + return winVersion; +} +#endif + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/helper/evntpost.cxx b/vcl/source/helper/evntpost.cxx new file mode 100644 index 0000000000..9e2106f492 --- /dev/null +++ b/vcl/source/helper/evntpost.cxx @@ -0,0 +1,57 @@ +/* -*- 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 <sal/config.h> + +#include <tools/debug.hxx> +#include <vcl/evntpost.hxx> +#include <vcl/svapp.hxx> + +namespace vcl +{ + +EventPoster::EventPoster( const Link<LinkParamNone*,void>& rLink ) + : m_aLink(rLink) +{ + m_nId = nullptr; +} + +EventPoster::~EventPoster() +{ + DBG_TESTSOLARMUTEX(); + if ( m_nId ) + Application::RemoveUserEvent( m_nId ); +} + +void EventPoster::Post() +{ + DBG_TESTSOLARMUTEX(); + m_nId = Application::PostUserEvent( LINK( this, EventPoster, DoEvent_Impl ) ); +} + +IMPL_LINK( EventPoster, DoEvent_Impl, void*, /*p*/, void ) +{ + DBG_TESTSOLARMUTEX(); + m_nId = nullptr; + m_aLink.Call( nullptr ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/helper/idletask.cxx b/vcl/source/helper/idletask.cxx new file mode 100644 index 0000000000..7df0514912 --- /dev/null +++ b/vcl/source/helper/idletask.cxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#include <vcl/idletask.hxx> +#include <vcl/svapp.hxx> + +//constructor of IdleTask Class +IdleTask::IdleTask() + : flag(false) +{ + //setting the Priority of Idle task to LOW, LOWEST + maIdle.SetPriority(TaskPriority::LOWEST); + //set idle for callback + maIdle.SetInvokeHandler(LINK(this, IdleTask, FlipFlag)); + //starting the idle + maIdle.Start(); +} + +//GetFlag() of IdleTask Class +bool IdleTask::GetFlag() const +{ + //returning the status of current flag + return flag; +} + +//Callback function of IdleTask Class +IMPL_LINK(IdleTask, FlipFlag, Timer*, , void) +{ + //setting the flag to make sure that low priority idle task has been dispatched + flag = true; +} + +void IdleTask::waitUntilIdleDispatched() +{ + //creating instance of IdleTask Class + IdleTask idleTask; + while (!idleTask.GetFlag()) + { + //dispatching all the events via VCL main-loop + SolarMutexGuard aGuard; + Application::Yield(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/source/helper/lazydelete.cxx b/vcl/source/helper/lazydelete.cxx new file mode 100644 index 0000000000..af1f9fcb33 --- /dev/null +++ b/vcl/source/helper/lazydelete.cxx @@ -0,0 +1,58 @@ +/* -*- 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 <vcl/lazydelete.hxx> +#include <svdata.hxx> +#include <sal/log.hxx> + +namespace vcl +{ +DeleteOnDeinitBase::~DeleteOnDeinitBase() +{ + ImplSVData* pSVData = ImplGetSVData(); + if (!pSVData) + return; + auto& rList = pSVData->maDeinitDeleteList; + std::erase(rList, this); +} + +void DeleteOnDeinitBase::addDeinitContainer(DeleteOnDeinitBase* i_pContainer) +{ + ImplSVData* pSVData = ImplGetSVData(); + + SAL_WARN_IF(pSVData->mbDeInit, "vcl", "DeleteOnDeinit added after DeiInitVCL !"); + if (pSVData->mbDeInit) + return; + + pSVData->maDeinitDeleteList.push_back(i_pContainer); +} + +void DeleteOnDeinitBase::ImplDeleteOnDeInit() +{ + ImplSVData* pSVData = ImplGetSVData(); + for (auto const& deinitDelete : pSVData->maDeinitDeleteList) + { + deinitDelete->doCleanup(); + } + pSVData->maDeinitDeleteList.clear(); +} + +} // namespace vcl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/helper/strhelper.cxx b/vcl/source/helper/strhelper.cxx new file mode 100644 index 0000000000..ebe48d1200 --- /dev/null +++ b/vcl/source/helper/strhelper.cxx @@ -0,0 +1,380 @@ +/* -*- 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 <strhelper.hxx> + +namespace { + +bool isSpace( sal_Unicode cChar ) +{ + return + cChar == ' ' || cChar == '\t' || + cChar == '\r' || cChar == '\n' || + cChar == 0x0c || cChar == 0x0b; +} + +bool isProtect( sal_Unicode cChar ) +{ + return cChar == '`' || cChar == '\'' || cChar == '"'; +} + +void CopyUntil( char*& pTo, const char*& pFrom, char cUntil, bool bIncludeUntil = false ) +{ + do + { + if( *pFrom == '\\' ) + { + pFrom++; + if( *pFrom ) + { + *pTo = *pFrom; + pTo++; + } + } + else if( bIncludeUntil || ! isProtect( *pFrom ) ) + { + *pTo = *pFrom; + pTo++; + } + pFrom++; + } while( *pFrom && *pFrom != cUntil ); + // copy the terminating character unless zero or protector + if( ! isProtect( *pFrom ) || bIncludeUntil ) + { + *pTo = *pFrom; + if( *pTo ) + pTo++; + } + if( *pFrom ) + pFrom++; +} + +void CopyUntil( sal_Unicode*& pTo, const sal_Unicode*& pFrom, sal_Unicode cUntil, bool bIncludeUntil = false ) +{ + do + { + if( *pFrom == '\\' ) + { + pFrom++; + if( *pFrom ) + { + *pTo = *pFrom; + pTo++; + } + } + else if( bIncludeUntil || ! isProtect( *pFrom ) ) + { + *pTo = *pFrom; + pTo++; + } + if( *pFrom ) + pFrom++; + } while( *pFrom && *pFrom != cUntil ); + // copy the terminating character unless zero or protector + if( ! isProtect( *pFrom ) || bIncludeUntil ) + { + *pTo = *pFrom; + if( *pTo ) + pTo++; + } + if( *pFrom ) + pFrom++; +} + +} + +namespace psp { + +OUString GetCommandLineToken( int nToken, const OUString& rLine ) +{ + sal_Int32 nLen = rLine.getLength(); + if( ! nLen ) + return OUString(); + + int nActualToken = 0; + sal_Unicode* pBuffer = static_cast<sal_Unicode*>(alloca( sizeof(sal_Unicode)*( nLen + 1 ) )); + const sal_Unicode* pRun = rLine.getStr(); + sal_Unicode* pLeap = nullptr; + + while( *pRun && nActualToken <= nToken ) + { + while( *pRun && isSpace( *pRun ) ) + pRun++; + pLeap = pBuffer; + while( *pRun && ! isSpace( *pRun ) ) + { + if( *pRun == '\\' ) + { + // escapement + pRun++; + *pLeap = *pRun; + pLeap++; + if( *pRun ) + pRun++; + } + else if( *pRun == '`' ) + CopyUntil( pLeap, pRun, '`' ); + else if( *pRun == '\'' ) + CopyUntil( pLeap, pRun, '\'' ); + else if( *pRun == '"' ) + CopyUntil( pLeap, pRun, '"' ); + else + { + *pLeap = *pRun; + pLeap++; + pRun++; + } + } + if( nActualToken != nToken ) + pBuffer[0] = 0; + nActualToken++; + } + + *pLeap = 0; + + return OUString(pBuffer); +} + +OString GetCommandLineToken(int nToken, const OString& rLine) +{ + sal_Int32 nLen = rLine.getLength(); + if (!nLen) + return rLine; + + int nActualToken = 0; + char* pBuffer = static_cast<char*>(alloca( nLen + 1 )); + const char* pRun = rLine.getStr(); + char* pLeap = nullptr; + + while( *pRun && nActualToken <= nToken ) + { + while( *pRun && isSpace( *pRun ) ) + pRun++; + pLeap = pBuffer; + while( *pRun && ! isSpace( *pRun ) ) + { + if( *pRun == '\\' ) + { + // escapement + pRun++; + *pLeap = *pRun; + pLeap++; + if( *pRun ) + pRun++; + } + else if( *pRun == '`' ) + CopyUntil( pLeap, pRun, '`' ); + else if( *pRun == '\'' ) + CopyUntil( pLeap, pRun, '\'' ); + else if( *pRun == '"' ) + CopyUntil( pLeap, pRun, '"' ); + else + { + *pLeap = *pRun; + pLeap++; + pRun++; + } + } + if( nActualToken != nToken ) + pBuffer[0] = 0; + nActualToken++; + } + + *pLeap = 0; + + return pBuffer; +} + +int GetCommandLineTokenCount(const OUString& rLine) +{ + if (rLine.isEmpty()) + return 0; + + int nTokenCount = 0; + const sal_Unicode *pRun = rLine.getStr(); + + while( *pRun ) + { + while( *pRun && isSpace( *pRun ) ) + pRun++; + if( ! *pRun ) + break; + while( *pRun && ! isSpace( *pRun ) ) + { + if( *pRun == '\\' ) + { + // escapement + pRun++; + if( *pRun ) + pRun++; + } + else if( *pRun == '`' ) + { + do pRun++; while( *pRun && *pRun != '`' ); + if( *pRun ) + pRun++; + } + else if( *pRun == '\'' ) + { + do pRun++; while( *pRun && *pRun != '\'' ); + if( *pRun ) + pRun++; + } + else if( *pRun == '"' ) + { + do pRun++; while( *pRun && *pRun != '"' ); + if( *pRun ) + pRun++; + } + else + pRun++; + } + nTokenCount++; + } + + return nTokenCount; +} + +OUString WhitespaceToSpace( std::u16string_view rLine, bool bProtect ) +{ + size_t nLen = rLine.size(); + if( ! nLen ) + return OUString(); + + sal_Unicode *pBuffer = static_cast<sal_Unicode*>(alloca( sizeof(sal_Unicode)*(nLen + 1) )); + const sal_Unicode *pRun = rLine.data(); + const sal_Unicode * const pEnd = rLine.data() + rLine.size(); + sal_Unicode *pLeap = pBuffer; + + while( pRun != pEnd ) + { + if( pRun != pEnd && isSpace( *pRun ) ) + { + *pLeap = ' '; + pLeap++; + pRun++; + } + while( pRun != pEnd && isSpace( *pRun ) ) + pRun++; + while( pRun != pEnd && ! isSpace( *pRun ) ) + { + if( *pRun == '\\' ) + { + // escapement + pRun++; + *pLeap = *pRun; + pLeap++; + if( pRun != pEnd ) + pRun++; + } + else if( bProtect && *pRun == '`' ) + CopyUntil( pLeap, pRun, '`', true ); + else if( bProtect && *pRun == '\'' ) + CopyUntil( pLeap, pRun, '\'', true ); + else if( bProtect && *pRun == '"' ) + CopyUntil( pLeap, pRun, '"', true ); + else + { + *pLeap = *pRun; + ++pLeap; + ++pRun; + } + } + } + + *pLeap = 0; + + // there might be a space at beginning or end + if (pLeap > pBuffer) + { + pLeap--; + if( *pLeap == ' ' ) + *pLeap = 0; + } + + return OUString(*pBuffer == ' ' ? pBuffer+1 : pBuffer); +} + +OString WhitespaceToSpace(std::string_view rLine) +{ + size_t nLen = rLine.size(); + if (!nLen) + return OString(); + + char *pBuffer = static_cast<char*>(alloca( nLen + 1 )); + const char *pRun = rLine.data(); + const char * const pEnd = rLine.data() + rLine.size(); + char *pLeap = pBuffer; + + while( pRun != pEnd ) + { + if( pRun != pEnd && isSpace( *pRun ) ) + { + *pLeap = ' '; + pLeap++; + pRun++; + } + while( pRun != pEnd && isSpace( *pRun ) ) + pRun++; + while( pRun != pEnd && ! isSpace( *pRun ) ) + { + if( *pRun == '\\' ) + { + // escapement + pRun++; + *pLeap = *pRun; + pLeap++; + if( pRun != pEnd ) + pRun++; + } + else if( *pRun == '`' ) + CopyUntil( pLeap, pRun, '`', true ); + else if( *pRun == '\'' ) + CopyUntil( pLeap, pRun, '\'', true ); + else if( *pRun == '"' ) + CopyUntil( pLeap, pRun, '"', true ); + else + { + *pLeap = *pRun; + ++pLeap; + ++pRun; + } + } + } + + *pLeap = 0; + + // there might be a space at beginning or end + assert(pLeap > pBuffer); + pLeap--; +#if defined(__GNUC__) && (__GNUC__ == 12 || __GNUC__ == 13) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#endif + if( *pLeap == ' ' ) + *pLeap = 0; +#if defined(__GNUC__) && (__GNUC__ == 12 || __GNUC__ == 13) +#pragma GCC diagnostic pop +#endif + return *pBuffer == ' ' ? pBuffer+1 : pBuffer; +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/helper/svtaccessiblefactory.cxx b/vcl/source/helper/svtaccessiblefactory.cxx new file mode 100644 index 0000000000..fa9e151fcc --- /dev/null +++ b/vcl/source/helper/svtaccessiblefactory.cxx @@ -0,0 +1,289 @@ +/* -*- 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 <config_feature_desktop.h> +#include <config_wasm_strip.h> + +#include <vcl/svtaccessiblefactory.hxx> +#include <vcl/accessiblefactory.hxx> +#include <vcl/accessibletable.hxx> +#include <vcl/accessibletableprovider.hxx> + +#include <tools/svlibrary.h> +#include <tools/debug.hxx> + +#include <osl/module.h> +#include <osl/diagnose.h> +#include <rtl/ref.hxx> + +namespace vcl +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::accessibility; + + namespace + { +#ifndef DISABLE_DYNLOADING + oslModule s_hAccessibleImplementationModule = nullptr; +#endif +#if HAVE_FEATURE_DESKTOP +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + GetSvtAccessibilityComponentFactory s_pAccessibleFactoryFunc = nullptr; +#endif +#endif + ::rtl::Reference< IAccessibleFactory > s_pFactory; + + + //= AccessibleDummyFactory + + class AccessibleDummyFactory: + public IAccessibleFactory + { + public: + AccessibleDummyFactory(); + AccessibleDummyFactory(const AccessibleDummyFactory&) = delete; + AccessibleDummyFactory& operator=(const AccessibleDummyFactory&) = delete; + + protected: + virtual ~AccessibleDummyFactory() override; + + public: + // IAccessibleFactory + virtual vcl::IAccessibleTabListBox* + createAccessibleTabListBox( + const css::uno::Reference< css::accessibility::XAccessible >& /*rxParent*/, + SvHeaderTabListBox& /*rBox*/ + ) const override + { + return nullptr; + } + + virtual css::uno::Reference< css::accessibility::XAccessible > + createAccessibleTreeListBox( + SvTreeListBox& /*_rListBox*/, + const css::uno::Reference< css::accessibility::XAccessible >& /*_xParent*/ + ) const override + { + return nullptr; + } + + virtual css::uno::Reference< css::accessibility::XAccessible > + createAccessibleIconView( + SvTreeListBox& /*_rListBox*/, + const css::uno::Reference< css::accessibility::XAccessible >& /*_xParent*/ + ) const override + { + return nullptr; + } + + virtual rtl::Reference<vcl::IAccessibleBrowseBox> + createAccessibleBrowseBox( + const css::uno::Reference< css::accessibility::XAccessible >& /*_rxParent*/, + vcl::IAccessibleTableProvider& /*_rBrowseBox*/ + ) const override + { + return nullptr; + } + + virtual rtl::Reference<table::IAccessibleTableControl> + createAccessibleTableControl( + const css::uno::Reference< css::accessibility::XAccessible >& /*_rxParent*/, + table::IAccessibleTable& /*_rTable*/ + ) const override + { + return nullptr; + } + + virtual css::uno::Reference< css::accessibility::XAccessible > + createAccessibleIconChoiceCtrl( + SvtIconChoiceCtrl& /*_rIconCtrl*/, + const css::uno::Reference< css::accessibility::XAccessible >& /*_xParent*/ + ) const override + { + return nullptr; + } + + virtual css::uno::Reference< css::accessibility::XAccessible > + createAccessibleTabBar( + TabBar& /*_rTabBar*/ + ) const override + { + return nullptr; + } + + virtual css::uno::Reference< css::accessibility::XAccessibleContext > + createAccessibleTextWindowContext( + VCLXWindow* /*pVclXWindow*/, TextEngine& /*rEngine*/, TextView& /*rView*/ + ) const override + { + return nullptr; + } + + virtual css::uno::Reference< css::accessibility::XAccessible > + createAccessibleBrowseBoxHeaderBar( + const css::uno::Reference< css::accessibility::XAccessible >& /*rxParent*/, + vcl::IAccessibleTableProvider& /*_rOwningTable*/, + AccessibleBrowseBoxObjType /*_eObjType*/ + ) const override + { + return nullptr; + } + + virtual css::uno::Reference< css::accessibility::XAccessible > + createAccessibleBrowseBoxTableCell( + const css::uno::Reference< css::accessibility::XAccessible >& /*_rxParent*/, + vcl::IAccessibleTableProvider& /*_rBrowseBox*/, + const css::uno::Reference< css::awt::XWindow >& /*_xFocusWindow*/, + sal_Int32 /*_nRowId*/, + sal_uInt16 /*_nColId*/, + sal_Int32 /*_nOffset*/ + ) const override + { + return nullptr; + } + + virtual css::uno::Reference< css::accessibility::XAccessible > + createAccessibleBrowseBoxHeaderCell( + sal_Int32 /*_nColumnRowId*/, + const css::uno::Reference< css::accessibility::XAccessible >& /*rxParent*/, + vcl::IAccessibleTableProvider& /*_rBrowseBox*/, + const css::uno::Reference< css::awt::XWindow >& /*_xFocusWindow*/, + AccessibleBrowseBoxObjType /*_eObjType*/ + ) const override + { + return nullptr; + } + + virtual css::uno::Reference< css::accessibility::XAccessible > + createAccessibleCheckBoxCell( + const css::uno::Reference< css::accessibility::XAccessible >& /*_rxParent*/, + vcl::IAccessibleTableProvider& /*_rBrowseBox*/, + const css::uno::Reference< css::awt::XWindow >& /*_xFocusWindow*/, + sal_Int32 /*_nRowPos*/, + sal_uInt16 /*_nColPos*/, + const TriState& /*_eState*/, + bool /*_bIsTriState*/ + ) const override + { + return nullptr; + } + + virtual css::uno::Reference< css::accessibility::XAccessible > + createEditBrowseBoxTableCellAccess( + const css::uno::Reference< css::accessibility::XAccessible >& /*_rxParent*/, + const css::uno::Reference< css::accessibility::XAccessible >& /*_rxControlAccessible*/, + const css::uno::Reference< css::awt::XWindow >& /*_rxFocusWindow*/, + vcl::IAccessibleTableProvider& /*_rBrowseBox*/, + sal_Int32 /*_nRowPos*/, + sal_uInt16 /*_nColPos*/ + ) const override + { + return nullptr; + } + }; + + + AccessibleDummyFactory::AccessibleDummyFactory() + { + } + + + AccessibleDummyFactory::~AccessibleDummyFactory() + { + } + + } + + + //= AccessibleFactoryAccess + + + AccessibleFactoryAccess::AccessibleFactoryAccess() + :m_bInitialized( false ) + { + } + +#if !ENABLE_WASM_STRIP_ACCESSIBILITY +#if HAVE_FEATURE_DESKTOP +#ifndef DISABLE_DYNLOADING + extern "C" { static void thisModule() {} } +#else + extern "C" void* getSvtAccessibilityComponentFactory(); +#endif +#endif // HAVE_FEATURE_DESKTOP +#endif // ENABLE_WASM_STRIP_ACCESSIBILITY + + void AccessibleFactoryAccess::ensureInitialized() + { + if ( m_bInitialized ) + return; + + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + +#if !ENABLE_WASM_STRIP_ACCESSIBILITY +#if HAVE_FEATURE_DESKTOP + // load the library implementing the factory + if (!s_pFactory) + { +#ifndef DISABLE_DYNLOADING + s_hAccessibleImplementationModule = osl_loadModuleRelative( &thisModule, u"" SVLIBRARY( "acc" ) ""_ustr.pData, 0 ); + if ( s_hAccessibleImplementationModule != nullptr ) + { + s_pAccessibleFactoryFunc = reinterpret_cast<GetSvtAccessibilityComponentFactory>( + osl_getFunctionSymbol( s_hAccessibleImplementationModule, u"getSvtAccessibilityComponentFactory"_ustr.pData )); + + } + OSL_ENSURE( s_pAccessibleFactoryFunc, "ac_registerClient: could not load the library, or not retrieve the needed symbol!" ); +#else + s_pAccessibleFactoryFunc = getSvtAccessibilityComponentFactory; +#endif // DISABLE_DYNLOADING + + // get a factory instance + if ( s_pAccessibleFactoryFunc ) + { + IAccessibleFactory* pFactory = static_cast< IAccessibleFactory* >( (*s_pAccessibleFactoryFunc)() ); + if ( pFactory ) + { + s_pFactory = pFactory; + pFactory->release(); + } + } + } +#endif // HAVE_FEATURE_DESKTOP +#endif // ENABLE_WASM_STRIP_ACCESSIBILITY + + if (!s_pFactory) + // the attempt to load the lib, or to create the factory, failed + // -> fall back to a dummy factory + s_pFactory = new AccessibleDummyFactory; + + m_bInitialized = true; + } + + IAccessibleFactory& AccessibleFactoryAccess::getFactory() + { + ensureInitialized(); + DBG_ASSERT( s_pFactory.is(), "AccessibleFactoryAccess::getFactory: at least a dummy factory should have been created!" ); + return *s_pFactory; + } + +} // namespace vcl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/helper/threadex.cxx b/vcl/source/helper/threadex.cxx new file mode 100644 index 0000000000..cbd342bd28 --- /dev/null +++ b/vcl/source/helper/threadex.cxx @@ -0,0 +1,68 @@ +/* -*- 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 <vcl/threadex.hxx> +#include <vcl/svapp.hxx> + +using namespace vcl; + +SolarThreadExecutor::SolarThreadExecutor() + : m_bTimeout(false) +{ +} + +SolarThreadExecutor::~SolarThreadExecutor() {} + +IMPL_LINK_NOARG(SolarThreadExecutor, worker, void*, void) +{ + if (!m_bTimeout) + { + m_aStart.set(); + doIt(); + m_aFinish.set(); + } +} + +void SolarThreadExecutor::execute() +{ + if (Application::IsMainThread()) + { + m_aStart.set(); + doIt(); + m_aFinish.set(); + } + else + { + m_aStart.reset(); + m_aFinish.reset(); + ImplSVEvent* nEvent = Application::PostUserEvent(LINK(this, SolarThreadExecutor, worker)); + SolarMutexReleaser aReleaser; + if (m_aStart.wait() == osl::Condition::result_timeout) + { + m_bTimeout = true; + Application::RemoveUserEvent(nEvent); + } + else + { + m_aFinish.wait(); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |