| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_canvas.hxx" |
| |
| #include <osl/mutex.hxx> |
| #include <osl/process.h> |
| #include <cppuhelper/implementationentry.hxx> |
| #include <cppuhelper/factory.hxx> |
| #include <cppuhelper/implbase3.hxx> |
| #include <vcl/configsettings.hxx> |
| |
| #include <com/sun/star/uno/XComponentContext.hpp> |
| #include <com/sun/star/lang/XServiceInfo.hpp> |
| #include <com/sun/star/lang/XSingleComponentFactory.hpp> |
| #include <com/sun/star/container/XContentEnumerationAccess.hpp> |
| #include <com/sun/star/container/XNameAccess.hpp> |
| #include <com/sun/star/container/XHierarchicalNameAccess.hpp> |
| #include <com/sun/star/beans/PropertyValue.hpp> |
| |
| #include <boost/bind.hpp> |
| #include <vector> |
| #include <utility> |
| #include <functional> |
| #include <algorithm> |
| |
| #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<OUString> SAL_CALL getSuppServices() |
| { |
| OUString name = OUSTR("com.sun.star.rendering.CanvasFactory"); |
| return Sequence<OUString>(&name, 1); |
| } |
| |
| //============================================================================== |
| class CanvasFactory |
| : public ::cppu::WeakImplHelper3< lang::XServiceInfo, |
| lang::XMultiComponentFactory, |
| lang::XMultiServiceFactory > |
| { |
| typedef std::pair<OUString,Sequence<OUString> > AvailPair; |
| typedef std::pair<OUString,OUString> CachePair; |
| typedef std::vector< AvailPair > AvailVector; |
| typedef std::vector< CachePair > CacheVector; |
| |
| |
| mutable ::osl::Mutex m_mutex; |
| Reference<XComponentContext> m_xContext; |
| Reference<container::XNameAccess> 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<XInterface> use( |
| OUString const & serviceName, |
| Sequence<Any> const & args, |
| Reference<XComponentContext> const & xContext ) const; |
| Reference<XInterface> lookupAndUse( |
| OUString const & serviceName, Sequence<Any> const & args, |
| Reference<XComponentContext> const & xContext ) const; |
| |
| public: |
| virtual ~CanvasFactory(); |
| CanvasFactory( Reference<XComponentContext> const & xContext ); |
| |
| // XServiceInfo |
| virtual OUString SAL_CALL getImplementationName() throw (RuntimeException); |
| virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) |
| throw (RuntimeException); |
| virtual Sequence<OUString> SAL_CALL getSupportedServiceNames() |
| throw (RuntimeException); |
| |
| // XMultiComponentFactory |
| virtual Sequence<OUString> SAL_CALL getAvailableServiceNames() |
| throw (RuntimeException); |
| virtual Reference<XInterface> SAL_CALL createInstanceWithContext( |
| OUString const & name, |
| Reference<XComponentContext> const & xContext ) throw (Exception); |
| virtual Reference<XInterface> SAL_CALL |
| createInstanceWithArgumentsAndContext( |
| OUString const & name, |
| Sequence<Any> const & args, |
| Reference<XComponentContext> const & xContext ) throw (Exception); |
| |
| // XMultiServiceFactory |
| virtual Reference<XInterface> SAL_CALL createInstance( |
| OUString const & name ) |
| throw (Exception); |
| virtual Reference<XInterface> SAL_CALL createInstanceWithArguments( |
| OUString const & name, Sequence<Any> const & args ) |
| throw (Exception); |
| }; |
| |
| CanvasFactory::CanvasFactory( Reference<XComponentContext> 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<lang::XMultiServiceFactory> 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<Any>( &propValue, 1 ) ), |
| UNO_QUERY_THROW ); |
| |
| propValue = makeAny( |
| beans::PropertyValue( |
| OUSTR("nodepath"), -1, |
| makeAny( OUSTR("/org.openoffice.Office.Canvas/CanvasServiceList") ), |
| beans::PropertyState_DIRECT_VALUE ) ); |
| |
| Reference<container::XNameAccess> xNameAccess( |
| xConfigProvider->createInstanceWithArguments( |
| OUSTR("com.sun.star.configuration.ConfigurationAccess"), |
| Sequence<Any>( &propValue, 1 ) ), UNO_QUERY_THROW ); |
| Reference<container::XHierarchicalNameAccess> xHierarchicalNameAccess( |
| xNameAccess, UNO_QUERY_THROW); |
| |
| Sequence<OUString> serviceNames = xNameAccess->getElementNames(); |
| const OUString* pCurr = serviceNames.getConstArray(); |
| const OUString* const pEnd = pCurr + serviceNames.getLength(); |
| while( pCurr != pEnd ) |
| { |
| Reference<container::XNameAccess> xEntryNameAccess( |
| xHierarchicalNameAccess->getByHierarchicalName(*pCurr), |
| UNO_QUERY ); |
| |
| if( xEntryNameAccess.is() ) |
| { |
| Sequence<OUString> 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<OUString> 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<XInterface> create( Reference<XComponentContext> 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<OUString> CanvasFactory::getSupportedServiceNames() |
| throw (RuntimeException) |
| { |
| return getSuppServices(); |
| } |
| |
| // XMultiComponentFactory |
| //______________________________________________________________________________ |
| Sequence<OUString> CanvasFactory::getAvailableServiceNames() |
| throw (RuntimeException) |
| { |
| Sequence<OUString> aServiceNames(m_aAvailableImplementations.size()); |
| std::transform(m_aAvailableImplementations.begin(), |
| m_aAvailableImplementations.end(), |
| aServiceNames.getArray(), |
| std::select1st<AvailPair>()); |
| return aServiceNames; |
| } |
| |
| //______________________________________________________________________________ |
| Reference<XInterface> CanvasFactory::createInstanceWithContext( |
| OUString const & name, Reference<XComponentContext> const & xContext ) |
| throw (Exception) |
| { |
| return createInstanceWithArgumentsAndContext( |
| name, Sequence<Any>(), xContext ); |
| } |
| |
| //______________________________________________________________________________ |
| Reference<XInterface> CanvasFactory::use( |
| OUString const & serviceName, |
| Sequence<Any> const & args, |
| Reference<XComponentContext> const & xContext ) const |
| { |
| try { |
| return m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( |
| serviceName, args, xContext); |
| } |
| catch (RuntimeException &) |
| { |
| throw; |
| } |
| catch (Exception &) |
| { |
| return Reference<XInterface>(); |
| } |
| } |
| |
| //______________________________________________________________________________ |
| 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<XInterface> CanvasFactory::lookupAndUse( |
| OUString const & serviceName, Sequence<Any> const & args, |
| Reference<XComponentContext> 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( |
| std::select1st<CachePair>(), |
| _1)))) != aEnd ) |
| { |
| Reference<XInterface> 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( |
| std::select1st<AvailPair>(), |
| _1)))) == aAvailEnd ) |
| { |
| return Reference<XInterface>(); |
| } |
| |
| 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( |
| std::select1st<AvailPair>(), |
| _1)))) == aAAEnd ) |
| { |
| return Reference<XInterface>(); |
| } |
| |
| 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( |
| std::select1st<AvailPair>(), |
| _1)))) == aAccelEnd ) |
| { |
| return Reference<XInterface>(); |
| } |
| |
| const Sequence<OUString> aPreferredImpls( aAvailImplsMatch->second ); |
| const OUString* pCurrImpl = aPreferredImpls.getConstArray(); |
| const OUString* const pEndImpl = pCurrImpl + aPreferredImpls.getLength(); |
| |
| const Sequence<OUString> aAAImpls( aAAImplsMatch->second ); |
| const OUString* const pFirstAAImpl = aAAImpls.getConstArray(); |
| const OUString* const pEndAAImpl = pFirstAAImpl + aAAImpls.getLength(); |
| |
| const Sequence<OUString> 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<XInterface> 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<XInterface>(); |
| } |
| |
| //______________________________________________________________________________ |
| Reference<XInterface> CanvasFactory::createInstanceWithArgumentsAndContext( |
| OUString const & preferredOne, Sequence<Any> const & args, |
| Reference<XComponentContext> const & xContext ) throw (Exception) |
| { |
| Reference<XInterface> xCanvas( |
| lookupAndUse( preferredOne, args, xContext ) ); |
| if(xCanvas.is()) |
| return xCanvas; |
| |
| // last resort: try service name directly |
| return use( preferredOne, args, xContext ); |
| } |
| |
| // XMultiServiceFactory |
| //______________________________________________________________________________ |
| Reference<XInterface> CanvasFactory::createInstance( OUString const & name ) |
| throw (Exception) |
| { |
| return createInstanceWithArgumentsAndContext( |
| name, Sequence<Any>(), m_xContext ); |
| } |
| |
| //______________________________________________________________________________ |
| Reference<XInterface> CanvasFactory::createInstanceWithArguments( |
| OUString const & name, Sequence<Any> 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" { |
| |
| void SAL_CALL component_getImplementationEnvironment( |
| const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) |
| { |
| *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; |
| } |
| |
| void * SAL_CALL component_getFactory( |
| sal_Char const * pImplName, |
| lang::XMultiServiceFactory * pServiceManager, |
| registry::XRegistryKey * pRegistryKey ) |
| { |
| return ::cppu::component_getFactoryHelper( |
| pImplName, pServiceManager, pRegistryKey, s_entries ); |
| } |
| |
| } |
| |