/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_canvas.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) #define ARLEN(x) (sizeof (x) / sizeof *(x)) using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using ::rtl::OUString; namespace { OUString SAL_CALL getImplName() { return OUSTR("com.sun.star.comp.rendering.CanvasFactory"); } Sequence SAL_CALL getSuppServices() { OUString name = OUSTR("com.sun.star.rendering.CanvasFactory"); return Sequence(&name, 1); } //============================================================================== class CanvasFactory : public ::cppu::WeakImplHelper3< lang::XServiceInfo, lang::XMultiComponentFactory, lang::XMultiServiceFactory > { typedef std::pair > AvailPair; typedef std::pair CachePair; typedef std::vector< AvailPair > AvailVector; typedef std::vector< CachePair > CacheVector; mutable ::osl::Mutex m_mutex; Reference m_xContext; Reference m_xCanvasConfigNameAccess; AvailVector m_aAvailableImplementations; AvailVector m_aAcceleratedImplementations; AvailVector m_aAAImplementations; mutable CacheVector m_aCachedImplementations; mutable bool m_bCacheHasForcedLastImpl; mutable bool m_bCacheHasUseAcceleratedEntry; mutable bool m_bCacheHasUseAAEntry; void checkConfigFlag( bool& r_bFlag, bool& r_CacheFlag, const OUString& nodeName ) const; Reference use( OUString const & serviceName, Sequence const & args, Reference const & xContext ) const; Reference lookupAndUse( OUString const & serviceName, Sequence const & args, Reference const & xContext ) const; public: virtual ~CanvasFactory(); CanvasFactory( Reference const & xContext ); // XServiceInfo virtual OUString SAL_CALL getImplementationName() throw (RuntimeException); virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) throw (RuntimeException); virtual Sequence SAL_CALL getSupportedServiceNames() throw (RuntimeException); // XMultiComponentFactory virtual Sequence SAL_CALL getAvailableServiceNames() throw (RuntimeException); virtual Reference SAL_CALL createInstanceWithContext( OUString const & name, Reference const & xContext ) throw (Exception); virtual Reference SAL_CALL createInstanceWithArgumentsAndContext( OUString const & name, Sequence const & args, Reference const & xContext ) throw (Exception); // XMultiServiceFactory virtual Reference SAL_CALL createInstance( OUString const & name ) throw (Exception); virtual Reference SAL_CALL createInstanceWithArguments( OUString const & name, Sequence const & args ) throw (Exception); }; CanvasFactory::CanvasFactory( Reference const & xContext ) : m_mutex(), m_xContext(xContext), m_xCanvasConfigNameAccess(), m_aAvailableImplementations(), m_aAcceleratedImplementations(), m_aAAImplementations(), m_aCachedImplementations(), m_bCacheHasForcedLastImpl(), m_bCacheHasUseAcceleratedEntry(), m_bCacheHasUseAAEntry() { try { // read out configuration for preferred services: Reference xConfigProvider( m_xContext->getServiceManager()->createInstanceWithContext( OUSTR("com.sun.star.configuration.ConfigurationProvider"), m_xContext ), UNO_QUERY_THROW ); Any propValue( makeAny( beans::PropertyValue( OUSTR("nodepath"), -1, makeAny( OUSTR("/org.openoffice.Office.Canvas") ), beans::PropertyState_DIRECT_VALUE ) ) ); m_xCanvasConfigNameAccess.set( xConfigProvider->createInstanceWithArguments( OUSTR("com.sun.star.configuration.ConfigurationAccess"), Sequence( &propValue, 1 ) ), UNO_QUERY_THROW ); propValue = makeAny( beans::PropertyValue( OUSTR("nodepath"), -1, makeAny( OUSTR("/org.openoffice.Office.Canvas/CanvasServiceList") ), beans::PropertyState_DIRECT_VALUE ) ); Reference xNameAccess( xConfigProvider->createInstanceWithArguments( OUSTR("com.sun.star.configuration.ConfigurationAccess"), Sequence( &propValue, 1 ) ), UNO_QUERY_THROW ); Reference xHierarchicalNameAccess( xNameAccess, UNO_QUERY_THROW); Sequence serviceNames = xNameAccess->getElementNames(); const OUString* pCurr = serviceNames.getConstArray(); const OUString* const pEnd = pCurr + serviceNames.getLength(); while( pCurr != pEnd ) { Reference xEntryNameAccess( xHierarchicalNameAccess->getByHierarchicalName(*pCurr), UNO_QUERY ); if( xEntryNameAccess.is() ) { Sequence implementationList; if( (xEntryNameAccess->getByName( OUSTR("PreferredImplementations") ) >>= implementationList) ) m_aAvailableImplementations.push_back( std::make_pair(*pCurr,implementationList) ); if( (xEntryNameAccess->getByName( OUSTR("AcceleratedImplementations") ) >>= implementationList) ) m_aAcceleratedImplementations.push_back( std::make_pair(*pCurr,implementationList) ); if( (xEntryNameAccess->getByName( OUSTR("AntialiasingImplementations") ) >>= implementationList) ) m_aAAImplementations.push_back( std::make_pair(*pCurr,implementationList) ); } ++pCurr; } } catch (RuntimeException &) { throw; } catch (Exception&) { } if( m_aAvailableImplementations.empty() ) { // Ugh. Looks like configuration is borked. Fake minimal // setup. Sequence aServices(1); aServices[0] = OUSTR("com.sun.star.comp.rendering.Canvas.VCL"); m_aAvailableImplementations.push_back( std::make_pair(OUSTR("com.sun.star.rendering.Canvas"), aServices) ); aServices[0] = OUSTR("com.sun.star.comp.rendering.SpriteCanvas.VCL"); m_aAvailableImplementations.push_back( std::make_pair(OUSTR("com.sun.star.rendering.SpriteCanvas"), aServices) ); } } CanvasFactory::~CanvasFactory() { } //------------------------------------------------------------------------------ Reference create( Reference const & xContext ) { return static_cast< ::cppu::OWeakObject * >( new CanvasFactory( xContext ) ); } // XServiceInfo //______________________________________________________________________________ OUString CanvasFactory::getImplementationName() throw (RuntimeException) { return getImplName(); } //______________________________________________________________________________ sal_Bool CanvasFactory::supportsService( OUString const & serviceName ) throw (RuntimeException) { return serviceName.equals(getSuppServices()[0]); } //______________________________________________________________________________ Sequence CanvasFactory::getSupportedServiceNames() throw (RuntimeException) { return getSuppServices(); } // XMultiComponentFactory //______________________________________________________________________________ Sequence CanvasFactory::getAvailableServiceNames() throw (RuntimeException) { Sequence aServiceNames(m_aAvailableImplementations.size()); std::transform(m_aAvailableImplementations.begin(), m_aAvailableImplementations.end(), aServiceNames.getArray(), o3tl::select1st()); return aServiceNames; } //______________________________________________________________________________ Reference CanvasFactory::createInstanceWithContext( OUString const & name, Reference const & xContext ) throw (Exception) { return createInstanceWithArgumentsAndContext( name, Sequence(), xContext ); } //______________________________________________________________________________ Reference CanvasFactory::use( OUString const & serviceName, Sequence const & args, Reference const & xContext ) const { try { return m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( serviceName, args, xContext); } catch (RuntimeException &) { throw; } catch (Exception &) { return Reference(); } } //______________________________________________________________________________ void CanvasFactory::checkConfigFlag( bool& r_bFlag, bool& r_CacheFlag, const OUString& nodeName ) const { if( m_xCanvasConfigNameAccess.is() ) { m_xCanvasConfigNameAccess->getByName( nodeName ) >>= r_bFlag; if( r_CacheFlag != r_bFlag ) { // cache is invalid, because of different order of // elements r_CacheFlag = r_bFlag; m_aCachedImplementations.clear(); } } } //______________________________________________________________________________ Reference CanvasFactory::lookupAndUse( OUString const & serviceName, Sequence const & args, Reference const & xContext ) const { ::osl::MutexGuard guard(m_mutex); // forcing last entry from impl list, if config flag set bool bForceLastEntry(false); checkConfigFlag( bForceLastEntry, m_bCacheHasForcedLastImpl, OUSTR("ForceSafeServiceImpl") ); // use anti-aliasing canvas, if config flag set (or not existing) bool bUseAAEntry(true); checkConfigFlag( bUseAAEntry, m_bCacheHasUseAAEntry, OUSTR("UseAntialiasingCanvas") ); // use accelerated canvas, if config flag set (or not existing) bool bUseAcceleratedEntry(true); checkConfigFlag( bUseAcceleratedEntry, m_bCacheHasUseAcceleratedEntry, OUSTR("UseAcceleratedCanvas") ); // try to reuse last working implementation for given service name const CacheVector::iterator aEnd(m_aCachedImplementations.end()); CacheVector::iterator aMatch; if( (aMatch=std::find_if(m_aCachedImplementations.begin(), aEnd, boost::bind(&OUString::equals, boost::cref(serviceName), boost::bind( o3tl::select1st(), _1)))) != aEnd ) { Reference xCanvas( use( aMatch->second, args, xContext ) ); if(xCanvas.is()) return xCanvas; } // lookup in available service list const AvailVector::const_iterator aAvailEnd(m_aAvailableImplementations.end()); AvailVector::const_iterator aAvailImplsMatch; if( (aAvailImplsMatch=std::find_if(m_aAvailableImplementations.begin(), aAvailEnd, boost::bind(&OUString::equals, boost::cref(serviceName), boost::bind( o3tl::select1st(), _1)))) == aAvailEnd ) { return Reference(); } const AvailVector::const_iterator aAAEnd(m_aAAImplementations.end()); AvailVector::const_iterator aAAImplsMatch; if( (aAAImplsMatch=std::find_if(m_aAAImplementations.begin(), aAAEnd, boost::bind(&OUString::equals, boost::cref(serviceName), boost::bind( o3tl::select1st(), _1)))) == aAAEnd ) { return Reference(); } const AvailVector::const_iterator aAccelEnd(m_aAcceleratedImplementations.end()); AvailVector::const_iterator aAccelImplsMatch; if( (aAccelImplsMatch=std::find_if(m_aAcceleratedImplementations.begin(), aAccelEnd, boost::bind(&OUString::equals, boost::cref(serviceName), boost::bind( o3tl::select1st(), _1)))) == aAccelEnd ) { return Reference(); } const Sequence aPreferredImpls( aAvailImplsMatch->second ); const OUString* pCurrImpl = aPreferredImpls.getConstArray(); const OUString* const pEndImpl = pCurrImpl + aPreferredImpls.getLength(); const Sequence aAAImpls( aAAImplsMatch->second ); const OUString* const pFirstAAImpl = aAAImpls.getConstArray(); const OUString* const pEndAAImpl = pFirstAAImpl + aAAImpls.getLength(); const Sequence aAccelImpls( aAccelImplsMatch->second ); const OUString* const pFirstAccelImpl = aAccelImpls.getConstArray(); const OUString* const pEndAccelImpl = pFirstAccelImpl + aAccelImpls.getLength(); // force last entry from impl list, if config flag set if( bForceLastEntry ) pCurrImpl = pEndImpl-1; while( pCurrImpl != pEndImpl ) { const OUString aCurrName(pCurrImpl->trim()); // check whether given canvas service is listed in the // sequence of "accelerated canvas implementations" const bool bIsAcceleratedImpl( std::find_if(pFirstAccelImpl, pEndAccelImpl, boost::bind(&OUString::equals, boost::cref(aCurrName), boost::bind( &OUString::trim, _1))) != pEndAccelImpl ); // check whether given canvas service is listed in the // sequence of "antialiasing canvas implementations" const bool bIsAAImpl( std::find_if(pFirstAAImpl, pEndAAImpl, boost::bind(&OUString::equals, boost::cref(aCurrName), boost::bind( &OUString::trim, _1))) != pEndAAImpl ); // try to instantiate canvas *only* if either accel and AA // property match preference, *or*, if there's a mismatch, only // go for a less capable canvas (that effectively let those // pour canvas impls still work as fallbacks, should an // accelerated/AA one fail). Property implies configuration: // http://en.wikipedia.org/wiki/Truth_table#Logical_implication if( (!bIsAAImpl || bUseAAEntry) && (!bIsAcceleratedImpl || bUseAcceleratedEntry) ) { Reference xCanvas( use( pCurrImpl->trim(), args, xContext ) ); if(xCanvas.is()) { if( aMatch != aEnd ) { // cache entry exists, replace dysfunctional // implementation name aMatch->second = pCurrImpl->trim(); } else { // new service name, add new cache entry m_aCachedImplementations.push_back(std::make_pair(serviceName, pCurrImpl->trim())); } return xCanvas; } } ++pCurrImpl; } return Reference(); } //______________________________________________________________________________ Reference CanvasFactory::createInstanceWithArgumentsAndContext( OUString const & preferredOne, Sequence const & args, Reference const & xContext ) throw (Exception) { Reference xCanvas( lookupAndUse( preferredOne, args, xContext ) ); if(xCanvas.is()) return xCanvas; // last resort: try service name directly return use( preferredOne, args, xContext ); } // XMultiServiceFactory //______________________________________________________________________________ Reference CanvasFactory::createInstance( OUString const & name ) throw (Exception) { return createInstanceWithArgumentsAndContext( name, Sequence(), m_xContext ); } //______________________________________________________________________________ Reference CanvasFactory::createInstanceWithArguments( OUString const & name, Sequence const & args ) throw (Exception) { return createInstanceWithArgumentsAndContext( name, args, m_xContext ); } const ::cppu::ImplementationEntry s_entries [] = { { create, getImplName, getSuppServices, ::cppu::createSingleComponentFactory, 0, 0 }, { 0, 0, 0, 0, 0, 0 } }; } // anon namespace extern "C" { SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( sal_Char const * pImplName, lang::XMultiServiceFactory * pServiceManager, registry::XRegistryKey * pRegistryKey ) { return ::cppu::component_getFactoryHelper( pImplName, pServiceManager, pRegistryKey, s_entries ); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */