summaryrefslogtreecommitdiffstats
path: root/vcl/source/helper
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /vcl/source/helper
parentInitial commit. (diff)
downloadlibreoffice-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.cxx1346
-rw-r--r--vcl/source/helper/canvastools.cxx627
-rw-r--r--vcl/source/helper/commandinfoprovider.cxx477
-rw-r--r--vcl/source/helper/displayconnectiondispatch.cxx111
-rw-r--r--vcl/source/helper/driverblocklist.cxx769
-rw-r--r--vcl/source/helper/evntpost.cxx57
-rw-r--r--vcl/source/helper/idletask.cxx51
-rw-r--r--vcl/source/helper/lazydelete.cxx58
-rw-r--r--vcl/source/helper/strhelper.cxx380
-rw-r--r--vcl/source/helper/svtaccessiblefactory.cxx289
-rw-r--r--vcl/source/helper/threadex.cxx68
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: */