nss: upgrade to release 3.73
[LibreOffice.git] / forms / source / component / imgprod.cxx
blob3e79596bb07fc0f2ce6771ca454684a3ad82a363
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "imgprod.hxx"
22 #include <osl/diagnose.h>
23 #include <tools/debug.hxx>
24 #include <vcl/bitmapaccess.hxx>
25 #include <vcl/cvtgrf.hxx>
26 #include <vcl/svapp.hxx>
27 #include <unotools/ucbstreamhelper.hxx>
28 #include <cppuhelper/queryinterface.hxx>
29 #include <com/sun/star/awt/ImageStatus.hpp>
30 #include <com/sun/star/io/XInputStream.hpp>
32 #include <svtools/imageresourceaccess.hxx>
33 #include <comphelper/processfactory.hxx>
35 namespace {
37 class ImgProdLockBytes : public SvLockBytes
39 css::uno::Reference< css::io::XInputStream > xStmRef;
40 css::uno::Sequence<sal_Int8> maSeq;
42 public:
44 ImgProdLockBytes( SvStream* pStm, bool bOwner );
45 explicit ImgProdLockBytes( css::uno::Reference< css::io::XInputStream > const & rStreamRef );
47 virtual ErrCode ReadAt( sal_uInt64 nPos, void* pBuffer, std::size_t nCount, std::size_t * pRead ) const override;
48 virtual ErrCode WriteAt( sal_uInt64 nPos, const void* pBuffer, std::size_t nCount, std::size_t * pWritten ) override;
49 virtual ErrCode Flush() const override;
50 virtual ErrCode SetSize( sal_uInt64 nSize ) override;
51 virtual ErrCode Stat( SvLockBytesStat* ) const override;
56 ImgProdLockBytes::ImgProdLockBytes( SvStream* pStm, bool bOwner ) :
57 SvLockBytes( pStm, bOwner )
62 ImgProdLockBytes::ImgProdLockBytes( css::uno::Reference< css::io::XInputStream > const & rStmRef ) :
63 xStmRef( rStmRef )
65 if( !xStmRef.is() )
66 return;
68 const sal_uInt32 nBytesToRead = 65535;
69 sal_uInt32 nRead;
73 css::uno::Sequence< sal_Int8 > aReadSeq;
75 nRead = xStmRef->readSomeBytes( aReadSeq, nBytesToRead );
77 if( nRead )
79 const sal_uInt32 nOldLength = maSeq.getLength();
80 maSeq.realloc( nOldLength + nRead );
81 memcpy( maSeq.getArray() + nOldLength, aReadSeq.getConstArray(), aReadSeq.getLength() );
84 while( nBytesToRead == nRead );
87 ErrCode ImgProdLockBytes::ReadAt(sal_uInt64 const nPos,
88 void* pBuffer, std::size_t nCount, std::size_t * pRead) const
90 if( GetStream() )
92 const_cast<SvStream*>(GetStream())->ResetError();
93 const ErrCode nErr = SvLockBytes::ReadAt( nPos, pBuffer, nCount, pRead );
94 const_cast<SvStream*>(GetStream())->ResetError();
95 return nErr;
97 else
99 const std::size_t nSeqLen = maSeq.getLength();
101 if( nPos < nSeqLen )
103 if( ( nPos + nCount ) > nSeqLen )
104 nCount = nSeqLen - nPos;
106 memcpy( pBuffer, maSeq.getConstArray() + nPos, nCount );
107 *pRead = nCount;
109 else
110 *pRead = 0;
112 return ERRCODE_NONE;
117 ErrCode ImgProdLockBytes::WriteAt(sal_uInt64 const nPos,
118 const void* pBuffer, std::size_t nCount, std::size_t * pWritten)
120 if( GetStream() )
121 return SvLockBytes::WriteAt( nPos, pBuffer, nCount, pWritten );
122 else
124 DBG_ASSERT( xStmRef.is(), "ImgProdLockBytes::WriteAt: xInputStream has no reference..." );
125 return ERRCODE_IO_CANTWRITE;
130 ErrCode ImgProdLockBytes::Flush() const
132 return ERRCODE_NONE;
136 ErrCode ImgProdLockBytes::SetSize(sal_uInt64 const nSize)
138 if( GetStream() )
139 return SvLockBytes::SetSize( nSize );
140 else
142 OSL_FAIL( "ImgProdLockBytes::SetSize not supported for xInputStream..." );
143 return ERRCODE_IO_CANTWRITE;
148 ErrCode ImgProdLockBytes::Stat( SvLockBytesStat* pStat ) const
150 if( GetStream() )
151 return SvLockBytes::Stat( pStat );
152 else
154 DBG_ASSERT( xStmRef.is(), "ImgProdLockBytes::Stat: xInputStream has no reference..." );
155 pStat->nSize = maSeq.getLength();
156 return ERRCODE_NONE;
161 ImageProducer::ImageProducer()
162 : mnTransIndex(0)
163 , mbConsInit(false)
165 mpGraphic.reset( new Graphic );
168 ImageProducer::~ImageProducer()
173 // XInterface
174 css::uno::Any ImageProducer::queryInterface( const css::uno::Type & rType )
176 css::uno::Any aRet = ::cppu::queryInterface( rType,
177 static_cast< css::lang::XInitialization* >(this),
178 static_cast< css::awt::XImageProducer* >(this) );
179 return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ));
183 void ImageProducer::addConsumer( const css::uno::Reference< css::awt::XImageConsumer >& rxConsumer )
185 DBG_ASSERT( rxConsumer.is(), "::AddConsumer(...): No consumer referenced!" );
186 if( rxConsumer.is() )
187 maConsList.push_back( rxConsumer );
191 void ImageProducer::removeConsumer( const css::uno::Reference< css::awt::XImageConsumer >& rxConsumer )
193 ConsumerList_t::reverse_iterator riter = std::find(maConsList.rbegin(),maConsList.rend(),rxConsumer);
195 if (riter != maConsList.rend())
196 maConsList.erase(riter.base()-1);
200 void ImageProducer::SetImage( const OUString& rPath )
202 maURL = rPath;
203 mpGraphic->Clear();
204 mbConsInit = false;
205 mpStm.reset();
207 if ( ::svt::GraphicAccess::isSupportedURL( maURL ) )
209 mpStm = ::svt::GraphicAccess::getImageStream( ::comphelper::getProcessComponentContext(), maURL );
211 else if( !maURL.isEmpty() )
213 std::unique_ptr<SvStream> pIStm = ::utl::UcbStreamHelper::CreateStream( maURL, StreamMode::STD_READ );
214 if (pIStm)
215 mpStm.reset( new SvStream( new ImgProdLockBytes( pIStm.release(), true ) ) );
220 void ImageProducer::SetImage( SvStream& rStm )
222 maURL.clear();
223 mpGraphic->Clear();
224 mbConsInit = false;
226 mpStm.reset( new SvStream( new ImgProdLockBytes( &rStm, false ) ) );
230 void ImageProducer::setImage( css::uno::Reference< css::io::XInputStream > const & rInputStmRef )
232 maURL.clear();
233 mpGraphic->Clear();
234 mbConsInit = false;
235 mpStm.reset();
237 if( rInputStmRef.is() )
238 mpStm.reset( new SvStream( new ImgProdLockBytes( rInputStmRef ) ) );
242 void ImageProducer::NewDataAvailable()
244 if( ( GraphicType::NONE == mpGraphic->GetType() ) || mpGraphic->GetReaderContext() )
245 startProduction();
249 void ImageProducer::startProduction()
251 if( maConsList.empty() && !maDoneHdl.IsSet() )
252 return;
254 bool bNotifyEmptyGraphics = false;
256 // valid stream or filled graphic? => update consumers
257 if( mpStm || ( mpGraphic->GetType() != GraphicType::NONE ) )
259 // if we already have a graphic, we don't have to import again;
260 // graphic is cleared if a new Stream is set
261 if( ( mpGraphic->GetType() == GraphicType::NONE ) || mpGraphic->GetReaderContext() )
263 if ( ImplImportGraphic( *mpGraphic ) )
264 maDoneHdl.Call( mpGraphic.get() );
267 if( mpGraphic->GetType() != GraphicType::NONE )
268 ImplUpdateData( *mpGraphic );
269 else
270 bNotifyEmptyGraphics = true;
272 else
273 bNotifyEmptyGraphics = true;
275 if ( !bNotifyEmptyGraphics )
276 return;
278 // reset image
279 // create temporary list to hold interfaces
280 ConsumerList_t aTmp = maConsList;
282 // iterate through interfaces
283 for (auto const& elem : aTmp)
285 elem->init( 0, 0 );
286 elem->complete( css::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE, this );
289 maDoneHdl.Call( nullptr );
293 bool ImageProducer::ImplImportGraphic( Graphic& rGraphic )
295 if (!mpStm)
296 return false;
298 if( ERRCODE_IO_PENDING == mpStm->GetError() )
299 mpStm->ResetError();
301 mpStm->Seek( 0 );
303 bool bRet = GraphicConverter::Import( *mpStm, rGraphic ) == ERRCODE_NONE;
305 if( ERRCODE_IO_PENDING == mpStm->GetError() )
306 mpStm->ResetError();
308 return bRet;
312 void ImageProducer::ImplUpdateData( const Graphic& rGraphic )
314 ImplInitConsumer( rGraphic );
316 if( mbConsInit && !maConsList.empty() )
318 // create temporary list to hold interfaces
319 ConsumerList_t aTmp = maConsList;
321 ImplUpdateConsumer( rGraphic );
322 mbConsInit = false;
324 // iterate through interfaces
325 for (auto const& elem : aTmp)
326 elem->complete( css::awt::ImageStatus::IMAGESTATUS_STATICIMAGEDONE, this );
331 void ImageProducer::ImplInitConsumer( const Graphic& rGraphic )
333 sal_uInt32 nRMask = 0;
334 sal_uInt32 nGMask = 0;
335 sal_uInt32 nBMask = 0;
336 sal_uInt32 nAMask = 0;
337 sal_uInt32 nWidth = 0;
338 sal_uInt32 nHeight = 0;
339 sal_uInt8 nBitCount = 0;
340 css::uno::Sequence< sal_Int32 > aRGBPal;
341 rGraphic.GetBitmapEx().GetColorModel(aRGBPal, nRMask, nGMask, nBMask, nAMask, mnTransIndex, nWidth, nHeight, nBitCount);
343 // create temporary list to hold interfaces
344 ConsumerList_t aTmp = maConsList;
346 // iterate through interfaces
347 for (auto const& elem : aTmp)
349 elem->init( nWidth, nHeight );
350 elem->setColorModel( nBitCount,aRGBPal, nRMask, nGMask, nBMask, nAMask );
353 mbConsInit = true;
357 void ImageProducer::ImplUpdateConsumer( const Graphic& rGraphic )
359 BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
360 Bitmap aBmp( aBmpEx.GetBitmap() );
361 BitmapReadAccess* pBmpAcc = aBmp.AcquireReadAccess();
363 if( !pBmpAcc )
364 return;
366 Bitmap aMask( aBmpEx.GetMask() );
367 BitmapReadAccess* pMskAcc = !!aMask ? aMask.AcquireReadAccess() : nullptr;
368 const tools::Long nWidth = pBmpAcc->Width();
369 const tools::Long nHeight = pBmpAcc->Height();
370 const tools::Long nStartX = 0;
371 const tools::Long nEndX = nWidth - 1;
372 const tools::Long nStartY = 0;
373 const tools::Long nEndY = nHeight - 1;
374 const tools::Long nPartWidth = nEndX - nStartX + 1;
375 const tools::Long nPartHeight = nEndY - nStartY + 1;
377 if( !pMskAcc )
379 aMask = Bitmap( aBmp.GetSizePixel(), 1 );
380 aMask.Erase( COL_BLACK );
381 pMskAcc = aMask.AcquireReadAccess();
384 // create temporary list to hold interfaces
385 ConsumerList_t aTmp = maConsList;
387 if( pBmpAcc->HasPalette() )
389 const BitmapColor aWhite( pMskAcc->GetBestMatchingColor( COL_WHITE ) );
391 if( mnTransIndex < 256 )
393 css::uno::Sequence<sal_Int8> aData( nPartWidth * nPartHeight );
394 sal_Int8* pTmp = aData.getArray();
396 for( tools::Long nY = nStartY; nY <= nEndY; nY++ )
398 Scanline pScanlineMask = pMskAcc->GetScanline( nY );
399 Scanline pScanline = pBmpAcc->GetScanline( nY );
400 for( tools::Long nX = nStartX; nX <= nEndX; nX++ )
402 if( pMskAcc->GetPixelFromData( pScanlineMask, nX ) == aWhite )
403 *pTmp++ = sal::static_int_cast< sal_Int8 >(
404 mnTransIndex );
405 else
406 *pTmp++ = pBmpAcc->GetPixelFromData( pScanline, nX ).GetIndex();
410 // iterate through interfaces
411 for (auto const& elem : aTmp)
412 elem->setPixelsByBytes( nStartX, nStartY, nPartWidth, nPartHeight, aData, 0UL, nPartWidth );
414 else
416 css::uno::Sequence<sal_Int32> aData( nPartWidth * nPartHeight );
417 sal_Int32* pTmp = aData.getArray();
419 for( tools::Long nY = nStartY; nY <= nEndY; nY++ )
421 Scanline pScanlineMask = pMskAcc->GetScanline( nY );
422 Scanline pScanline = pBmpAcc->GetScanline( nY );
423 for( tools::Long nX = nStartX; nX <= nEndX; nX++ )
425 if( pMskAcc->GetPixelFromData( pScanlineMask, nX ) == aWhite )
426 *pTmp++ = mnTransIndex;
427 else
428 *pTmp++ = pBmpAcc->GetPixelFromData( pScanline, nX ).GetIndex();
432 // iterate through interfaces
433 for (auto const& elem : aTmp)
434 elem->setPixelsByLongs( nStartX, nStartY, nPartWidth, nPartHeight, aData, 0UL, nPartWidth );
437 else
439 css::uno::Sequence<sal_Int32> aData( nPartWidth * nPartHeight );
440 const BitmapColor aWhite( pMskAcc->GetBestMatchingColor( COL_WHITE ) );
441 sal_Int32* pTmp = aData.getArray();
443 for( tools::Long nY = nStartY; nY <= nEndY; nY++ )
445 Scanline pScanlineMask = pMskAcc->GetScanline( nY );
446 Scanline pScanline = pBmpAcc->GetScanline( nY );
447 for( tools::Long nX = nStartX; nX <= nEndX; nX++, pTmp++ )
449 const BitmapColor aCol( pBmpAcc->GetPixelFromData( pScanline, nX ) );
451 *pTmp = static_cast<sal_Int32>(aCol.GetRed()) << 24;
452 *pTmp |= static_cast<sal_Int32>(aCol.GetGreen()) << 16;
453 *pTmp |= static_cast<sal_Int32>(aCol.GetBlue()) << 8;
455 if( pMskAcc->GetPixelFromData( pScanlineMask, nX ) != aWhite )
456 *pTmp |= 0x000000ffUL;
460 // iterate through interfaces
461 for (auto const& elem : aTmp)
462 elem->setPixelsByLongs( nStartX, nStartY, nPartWidth, nPartHeight, aData, 0UL, nPartWidth );
465 Bitmap::ReleaseAccess( pBmpAcc );
466 Bitmap::ReleaseAccess( pMskAcc );
470 void ImageProducer::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
472 if ( aArguments.getLength() == 1 )
474 css::uno::Any aArg = aArguments.getConstArray()[0];
475 OUString aURL;
476 if ( aArg >>= aURL )
478 SetImage( aURL );
484 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
485 com_sun_star_form_ImageProducer_get_implementation(css::uno::XComponentContext*,
486 css::uno::Sequence<css::uno::Any> const &)
488 return cppu::acquire(new ImageProducer());
491 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */