/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::com::sun::star::uno; namespace { OUString SAL_CALL getImplName() { return OUString("com.sun.star.comp.rendering.CanvasFactory"); } Sequence SAL_CALL getSuppServices() { OUString name("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( configuration::theDefaultProvider::get( m_xContext ) ); Any propValue( makeAny( beans::PropertyValue( OUString("nodepath"), -1, makeAny( OUString("/org.openoffice.Office.Canvas") ), beans::PropertyState_DIRECT_VALUE ) ) ); m_xCanvasConfigNameAccess.set( xConfigProvider->createInstanceWithArguments( OUString("com.sun.star.configuration.ConfigurationAccess"), Sequence( &propValue, 1 ) ), UNO_QUERY_THROW ); propValue = makeAny( beans::PropertyValue( OUString("nodepath"), -1, makeAny( OUString("/org.openoffice.Office.Canvas/CanvasServiceList") ), beans::PropertyState_DIRECT_VALUE ) ); Reference xNameAccess( xConfigProvider->createInstanceWithArguments( OUString("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("PreferredImplementations") >>= implementationList) ) m_aAvailableImplementations.push_back( std::make_pair(*pCurr,implementationList) ); if( (xEntryNameAccess->getByName("AcceleratedImplementations") >>= implementationList) ) m_aAcceleratedImplementations.push_back( std::make_pair(*pCurr,implementationList) ); if( (xEntryNameAccess->getByName("AntialiasingImplementations") >>= implementationList) ) m_aAAImplementations.push_back( std::make_pair(*pCurr,implementationList) ); } ++pCurr; } } catch (const RuntimeException &) { throw; } catch (const Exception&) { } if( m_aAvailableImplementations.empty() ) { // Ugh. Looks like configuration is borked. Fake minimal // setup. Sequence aServices(1); aServices[0] = OUString("com.sun.star.comp.rendering.Canvas.VCL"); m_aAvailableImplementations.push_back( std::make_pair(OUString("com.sun.star.rendering.Canvas"), aServices) ); aServices[0] = OUString("com.sun.star.comp.rendering.SpriteCanvas.VCL"); m_aAvailableImplementations.push_back( std::make_pair(OUString("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 (css::lang::IllegalArgumentException &) { return Reference(); } catch (const RuntimeException &) { throw; } catch (const 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, OUString("ForceSafeServiceImpl") ); // use anti-aliasing canvas, if config flag set (or not existing) bool bUseAAEntry(true); checkConfigFlag( bUseAAEntry, m_bCacheHasUseAAEntry, OUString("UseAntialiasingCanvas") ); // use accelerated canvas, if config flag set (or not existing) bool bUseAcceleratedEntry(true); checkConfigFlag( bUseAcceleratedEntry, m_bCacheHasUseAcceleratedEntry, OUString("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 canvasfactory_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: */