diff options
Diffstat (limited to 'extensions/source/scanner/scanunx.cxx')
-rw-r--r-- | extensions/source/scanner/scanunx.cxx | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/extensions/source/scanner/scanunx.cxx b/extensions/source/scanner/scanunx.cxx new file mode 100644 index 000000000..6a81f5fbf --- /dev/null +++ b/extensions/source/scanner/scanunx.cxx @@ -0,0 +1,344 @@ +/* -*- 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 "scanner.hxx" +#include "sanedlg.hxx" +#include <o3tl/safeint.hxx> +#include <osl/thread.hxx> +#include <sal/log.hxx> +#include <vcl/svapp.hxx> +#include <memory> + +#include <com/sun/star/scanner/ScannerException.hpp> + +BitmapTransporter::BitmapTransporter() +{ + SAL_INFO("extensions.scanner", "BitmapTransporter"); +} + + +BitmapTransporter::~BitmapTransporter() +{ + SAL_INFO("extensions.scanner", "~BitmapTransporter"); +} + + +css::awt::Size BitmapTransporter::getSize() +{ + osl::MutexGuard aGuard( m_aProtector ); + css::awt::Size aRet; + + // ensure that there is at least a header + int nLen = m_aStream.TellEnd(); + if( nLen > 15 ) + { + int nPreviousPos = m_aStream.Tell(); + m_aStream.Seek( 4 ); + m_aStream.ReadInt32( aRet.Width ).ReadInt32( aRet.Height ); + m_aStream.Seek( nPreviousPos ); + } + else + aRet.Width = aRet.Height = 0; + + + return aRet; +} + + +Sequence< sal_Int8 > BitmapTransporter::getDIB() +{ + osl::MutexGuard aGuard( m_aProtector ); + int nPreviousPos = m_aStream.Tell(); + + // create return value + int nBytes = m_aStream.TellEnd(); + m_aStream.Seek( 0 ); + + Sequence< sal_Int8 > aValue( nBytes ); + m_aStream.ReadBytes( aValue.getArray(), nBytes ); + m_aStream.Seek( nPreviousPos ); + + return aValue; +} + +namespace { + +struct SaneHolder +{ + Sane m_aSane; + Reference< css::awt::XBitmap > m_xBitmap; + osl::Mutex m_aProtector; + ScanError m_nError; + bool m_bBusy; + + SaneHolder() : m_nError(ScanError_ScanErrorNone), m_bBusy(false) {} +}; + + typedef std::vector< std::shared_ptr<SaneHolder> > sanevec; + class allSanes + { + private: + int mnRefCount; + public: + sanevec m_aSanes; + allSanes() : mnRefCount(0) {} + void acquire(); + void release(); + }; + + void allSanes::acquire() + { + ++mnRefCount; + } + + void allSanes::release() + { + // was unused, now because of i99835: "Scanning interface not SANE API + // compliant" destroy all SaneHolder to get Sane Dtor called + --mnRefCount; + if (!mnRefCount) + m_aSanes.clear(); + } + + struct theSaneProtector : public rtl::Static<osl::Mutex, theSaneProtector> {}; + struct theSanes : public rtl::Static<allSanes, theSanes> {}; + +class ScannerThread : public osl::Thread +{ + std::shared_ptr<SaneHolder> m_pHolder; + Reference< css::lang::XEventListener > m_xListener; + ScannerManager* m_pManager; // just for the disposing call + +public: + virtual void SAL_CALL run() override; + virtual void SAL_CALL onTerminated() override { delete this; } +public: + ScannerThread( const std::shared_ptr<SaneHolder>& pHolder, + const Reference< css::lang::XEventListener >& listener, + ScannerManager* pManager ); + virtual ~ScannerThread() override; +}; + +} + +ScannerThread::ScannerThread(const std::shared_ptr<SaneHolder>& pHolder, + const Reference< css::lang::XEventListener >& listener, + ScannerManager* pManager) + : m_pHolder( pHolder ), m_xListener( listener ), m_pManager( pManager ) +{ + SAL_INFO("extensions.scanner", "ScannerThread"); +} + + +ScannerThread::~ScannerThread() +{ + SAL_INFO("extensions.scanner", "~ScannerThread"); +} + + +void ScannerThread::run() +{ + osl_setThreadName("ScannerThread"); + + osl::MutexGuard aGuard( m_pHolder->m_aProtector ); + BitmapTransporter* pTransporter = new BitmapTransporter; + Reference< XInterface > aIf( static_cast< OWeakObject* >( pTransporter ) ); + + m_pHolder->m_xBitmap.set( aIf, UNO_QUERY ); + + m_pHolder->m_bBusy = true; + if( m_pHolder->m_aSane.IsOpen() ) + { + int nOption = m_pHolder->m_aSane.GetOptionByName( "preview" ); + if( nOption != -1 ) + m_pHolder->m_aSane.SetOptionValue( nOption, false ); + + m_pHolder->m_nError = + m_pHolder->m_aSane.Start( *pTransporter ) ? + ScanError_ScanErrorNone : ScanError_ScanCanceled; + } + else + m_pHolder->m_nError = ScanError_ScannerNotAvailable; + + + Reference< XInterface > xXInterface( static_cast< OWeakObject* >( m_pManager ) ); + m_xListener->disposing( css::lang::EventObject(xXInterface) ); + m_pHolder->m_bBusy = false; +} + + +void ScannerManager::AcquireData() +{ + osl::MutexGuard aGuard( theSaneProtector::get() ); + theSanes::get().acquire(); +} + + +void ScannerManager::ReleaseData() +{ + osl::MutexGuard aGuard( theSaneProtector::get() ); + theSanes::get().release(); +} + + +css::awt::Size ScannerManager::getSize() +{ + css::awt::Size aRet; + aRet.Width = aRet.Height = 0; + return aRet; +} + + +Sequence< sal_Int8 > ScannerManager::getDIB() +{ + return Sequence< sal_Int8 >(); +} + + +Sequence< ScannerContext > ScannerManager::getAvailableScanners() +{ + osl::MutexGuard aGuard( theSaneProtector::get() ); + sanevec &rSanes = theSanes::get().m_aSanes; + + if( rSanes.empty() ) + { + auto pSaneHolder = std::make_shared<SaneHolder>(); + if( Sane::IsSane() ) + rSanes.push_back( pSaneHolder ); + } + + if( Sane::IsSane() ) + { + Sequence< ScannerContext > aRet(1); + aRet[0].ScannerName = "SANE"; + aRet[0].InternalData = 0; + return aRet; + } + + return Sequence< ScannerContext >(); +} + + +sal_Bool ScannerManager::configureScannerAndScan( ScannerContext& scanner_context, + const Reference< css::lang::XEventListener >& listener ) +{ + bool bRet; + bool bScan; + { + osl::MutexGuard aGuard( theSaneProtector::get() ); + sanevec &rSanes = theSanes::get().m_aSanes; + + SAL_INFO("extensions.scanner", "ScannerManager::configureScanner"); + + if( scanner_context.InternalData < 0 || o3tl::make_unsigned(scanner_context.InternalData) >= rSanes.size() ) + throw ScannerException( + "Scanner does not exist", + Reference< XScannerManager >( this ), + ScanError_InvalidContext + ); + + std::shared_ptr<SaneHolder> pHolder = rSanes[scanner_context.InternalData]; + if( pHolder->m_bBusy ) + throw ScannerException( + "Scanner is busy", + Reference< XScannerManager >( this ), + ScanError_ScanInProgress + ); + + pHolder->m_bBusy = true; + SaneDlg aDlg(Application::GetFrameWeld(mxDialogParent), pHolder->m_aSane, listener.is()); + bRet = aDlg.run(); + bScan = aDlg.getDoScan(); + pHolder->m_bBusy = false; + } + if ( bScan ) + startScan( scanner_context, listener ); + + return bRet; +} + + +void ScannerManager::startScan( const ScannerContext& scanner_context, + const Reference< css::lang::XEventListener >& listener ) +{ + osl::MutexGuard aGuard( theSaneProtector::get() ); + sanevec &rSanes = theSanes::get().m_aSanes; + + SAL_INFO("extensions.scanner", "ScannerManager::startScan"); + + if( scanner_context.InternalData < 0 || o3tl::make_unsigned(scanner_context.InternalData) >= rSanes.size() ) + throw ScannerException( + "Scanner does not exist", + Reference< XScannerManager >( this ), + ScanError_InvalidContext + ); + std::shared_ptr<SaneHolder> pHolder = rSanes[scanner_context.InternalData]; + if( pHolder->m_bBusy ) + throw ScannerException( + "Scanner is busy", + Reference< XScannerManager >( this ), + ScanError_ScanInProgress + ); + pHolder->m_bBusy = true; + + ScannerThread* pThread = new ScannerThread( pHolder, listener, this ); + pThread->create(); +} + + +ScanError ScannerManager::getError( const ScannerContext& scanner_context ) +{ + osl::MutexGuard aGuard( theSaneProtector::get() ); + sanevec &rSanes = theSanes::get().m_aSanes; + + if( scanner_context.InternalData < 0 || o3tl::make_unsigned(scanner_context.InternalData) >= rSanes.size() ) + throw ScannerException( + "Scanner does not exist", + Reference< XScannerManager >( this ), + ScanError_InvalidContext + ); + + std::shared_ptr<SaneHolder> pHolder = rSanes[scanner_context.InternalData]; + + return pHolder->m_nError; +} + + +Reference< css::awt::XBitmap > ScannerManager::getBitmap( const ScannerContext& scanner_context ) +{ + osl::MutexGuard aGuard( theSaneProtector::get() ); + sanevec &rSanes = theSanes::get().m_aSanes; + + if( scanner_context.InternalData < 0 || o3tl::make_unsigned(scanner_context.InternalData) >= rSanes.size() ) + throw ScannerException( + "Scanner does not exist", + Reference< XScannerManager >( this ), + ScanError_InvalidContext + ); + std::shared_ptr<SaneHolder> pHolder = rSanes[scanner_context.InternalData]; + + osl::MutexGuard aProtGuard( pHolder->m_aProtector ); + + Reference< css::awt::XBitmap > xRet( pHolder->m_xBitmap ); + pHolder->m_xBitmap.clear(); + + return xRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |