1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_canvas.hxx" 30 31 #include <osl/mutex.hxx> 32 #include <osl/process.h> 33 #include <cppuhelper/implementationentry.hxx> 34 #include <cppuhelper/factory.hxx> 35 #include <cppuhelper/implbase3.hxx> 36 #include <vcl/configsettings.hxx> 37 38 #include <com/sun/star/uno/XComponentContext.hpp> 39 #include <com/sun/star/lang/XServiceInfo.hpp> 40 #include <com/sun/star/lang/XSingleComponentFactory.hpp> 41 #include <com/sun/star/container/XContentEnumerationAccess.hpp> 42 #include <com/sun/star/container/XNameAccess.hpp> 43 #include <com/sun/star/container/XHierarchicalNameAccess.hpp> 44 #include <com/sun/star/beans/PropertyValue.hpp> 45 46 #include <boost/bind.hpp> 47 #include <vector> 48 #include <utility> 49 #include <functional> 50 #include <algorithm> 51 52 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) 53 #define ARLEN(x) (sizeof (x) / sizeof *(x)) 54 55 56 using namespace ::com::sun::star; 57 using namespace ::com::sun::star::uno; 58 using ::rtl::OUString; 59 60 namespace 61 { 62 63 OUString SAL_CALL getImplName() 64 { 65 return OUSTR("com.sun.star.comp.rendering.CanvasFactory"); 66 } 67 68 Sequence<OUString> SAL_CALL getSuppServices() 69 { 70 OUString name = OUSTR("com.sun.star.rendering.CanvasFactory"); 71 return Sequence<OUString>(&name, 1); 72 } 73 74 //============================================================================== 75 class CanvasFactory 76 : public ::cppu::WeakImplHelper3< lang::XServiceInfo, 77 lang::XMultiComponentFactory, 78 lang::XMultiServiceFactory > 79 { 80 typedef std::pair<OUString,Sequence<OUString> > AvailPair; 81 typedef std::pair<OUString,OUString> CachePair; 82 typedef std::vector< AvailPair > AvailVector; 83 typedef std::vector< CachePair > CacheVector; 84 85 86 mutable ::osl::Mutex m_mutex; 87 Reference<XComponentContext> m_xContext; 88 Reference<container::XNameAccess> m_xCanvasConfigNameAccess; 89 AvailVector m_aAvailableImplementations; 90 AvailVector m_aAcceleratedImplementations; 91 AvailVector m_aAAImplementations; 92 mutable CacheVector m_aCachedImplementations; 93 mutable bool m_bCacheHasForcedLastImpl; 94 mutable bool m_bCacheHasUseAcceleratedEntry; 95 mutable bool m_bCacheHasUseAAEntry; 96 97 void checkConfigFlag( bool& r_bFlag, 98 bool& r_CacheFlag, 99 const OUString& nodeName ) const; 100 Reference<XInterface> use( 101 OUString const & serviceName, 102 Sequence<Any> const & args, 103 Reference<XComponentContext> const & xContext ) const; 104 Reference<XInterface> lookupAndUse( 105 OUString const & serviceName, Sequence<Any> const & args, 106 Reference<XComponentContext> const & xContext ) const; 107 108 public: 109 virtual ~CanvasFactory(); 110 CanvasFactory( Reference<XComponentContext> const & xContext ); 111 112 // XServiceInfo 113 virtual OUString SAL_CALL getImplementationName() throw (RuntimeException); 114 virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) 115 throw (RuntimeException); 116 virtual Sequence<OUString> SAL_CALL getSupportedServiceNames() 117 throw (RuntimeException); 118 119 // XMultiComponentFactory 120 virtual Sequence<OUString> SAL_CALL getAvailableServiceNames() 121 throw (RuntimeException); 122 virtual Reference<XInterface> SAL_CALL createInstanceWithContext( 123 OUString const & name, 124 Reference<XComponentContext> const & xContext ) throw (Exception); 125 virtual Reference<XInterface> SAL_CALL 126 createInstanceWithArgumentsAndContext( 127 OUString const & name, 128 Sequence<Any> const & args, 129 Reference<XComponentContext> const & xContext ) throw (Exception); 130 131 // XMultiServiceFactory 132 virtual Reference<XInterface> SAL_CALL createInstance( 133 OUString const & name ) 134 throw (Exception); 135 virtual Reference<XInterface> SAL_CALL createInstanceWithArguments( 136 OUString const & name, Sequence<Any> const & args ) 137 throw (Exception); 138 }; 139 140 CanvasFactory::CanvasFactory( Reference<XComponentContext> const & xContext ) : 141 m_mutex(), 142 m_xContext(xContext), 143 m_xCanvasConfigNameAccess(), 144 m_aAvailableImplementations(), 145 m_aAcceleratedImplementations(), 146 m_aAAImplementations(), 147 m_aCachedImplementations(), 148 m_bCacheHasForcedLastImpl(), 149 m_bCacheHasUseAcceleratedEntry(), 150 m_bCacheHasUseAAEntry() 151 { 152 try 153 { 154 // read out configuration for preferred services: 155 Reference<lang::XMultiServiceFactory> xConfigProvider( 156 m_xContext->getServiceManager()->createInstanceWithContext( 157 OUSTR("com.sun.star.configuration.ConfigurationProvider"), 158 m_xContext ), UNO_QUERY_THROW ); 159 160 Any propValue( 161 makeAny( beans::PropertyValue( 162 OUSTR("nodepath"), -1, 163 makeAny( OUSTR("/org.openoffice.Office.Canvas") ), 164 beans::PropertyState_DIRECT_VALUE ) ) ); 165 166 m_xCanvasConfigNameAccess.set( 167 xConfigProvider->createInstanceWithArguments( 168 OUSTR("com.sun.star.configuration.ConfigurationAccess"), 169 Sequence<Any>( &propValue, 1 ) ), 170 UNO_QUERY_THROW ); 171 172 propValue = makeAny( 173 beans::PropertyValue( 174 OUSTR("nodepath"), -1, 175 makeAny( OUSTR("/org.openoffice.Office.Canvas/CanvasServiceList") ), 176 beans::PropertyState_DIRECT_VALUE ) ); 177 178 Reference<container::XNameAccess> xNameAccess( 179 xConfigProvider->createInstanceWithArguments( 180 OUSTR("com.sun.star.configuration.ConfigurationAccess"), 181 Sequence<Any>( &propValue, 1 ) ), UNO_QUERY_THROW ); 182 Reference<container::XHierarchicalNameAccess> xHierarchicalNameAccess( 183 xNameAccess, UNO_QUERY_THROW); 184 185 Sequence<OUString> serviceNames = xNameAccess->getElementNames(); 186 const OUString* pCurr = serviceNames.getConstArray(); 187 const OUString* const pEnd = pCurr + serviceNames.getLength(); 188 while( pCurr != pEnd ) 189 { 190 Reference<container::XNameAccess> xEntryNameAccess( 191 xHierarchicalNameAccess->getByHierarchicalName(*pCurr), 192 UNO_QUERY ); 193 194 if( xEntryNameAccess.is() ) 195 { 196 Sequence<OUString> implementationList; 197 if( (xEntryNameAccess->getByName( OUSTR("PreferredImplementations") ) >>= implementationList) ) 198 m_aAvailableImplementations.push_back( std::make_pair(*pCurr,implementationList) ); 199 if( (xEntryNameAccess->getByName( OUSTR("AcceleratedImplementations") ) >>= implementationList) ) 200 m_aAcceleratedImplementations.push_back( std::make_pair(*pCurr,implementationList) ); 201 if( (xEntryNameAccess->getByName( OUSTR("AntialiasingImplementations") ) >>= implementationList) ) 202 m_aAAImplementations.push_back( std::make_pair(*pCurr,implementationList) ); 203 } 204 205 ++pCurr; 206 } 207 } 208 catch (RuntimeException &) 209 { 210 throw; 211 } 212 catch (Exception&) 213 { 214 } 215 216 if( m_aAvailableImplementations.empty() ) 217 { 218 // Ugh. Looks like configuration is borked. Fake minimal 219 // setup. 220 Sequence<OUString> aServices(1); 221 aServices[0] = OUSTR("com.sun.star.comp.rendering.Canvas.VCL"); 222 m_aAvailableImplementations.push_back( std::make_pair(OUSTR("com.sun.star.rendering.Canvas"), 223 aServices) ); 224 225 aServices[0] = OUSTR("com.sun.star.comp.rendering.SpriteCanvas.VCL"); 226 m_aAvailableImplementations.push_back( std::make_pair(OUSTR("com.sun.star.rendering.SpriteCanvas"), 227 aServices) ); 228 } 229 } 230 231 CanvasFactory::~CanvasFactory() 232 { 233 } 234 235 //------------------------------------------------------------------------------ 236 Reference<XInterface> create( Reference<XComponentContext> const & xContext ) 237 { 238 return static_cast< ::cppu::OWeakObject * >( 239 new CanvasFactory( xContext ) ); 240 } 241 242 // XServiceInfo 243 //______________________________________________________________________________ 244 OUString CanvasFactory::getImplementationName() throw (RuntimeException) 245 { 246 return getImplName(); 247 } 248 249 //______________________________________________________________________________ 250 sal_Bool CanvasFactory::supportsService( OUString const & serviceName ) 251 throw (RuntimeException) 252 { 253 return serviceName.equals(getSuppServices()[0]); 254 } 255 256 //______________________________________________________________________________ 257 Sequence<OUString> CanvasFactory::getSupportedServiceNames() 258 throw (RuntimeException) 259 { 260 return getSuppServices(); 261 } 262 263 // XMultiComponentFactory 264 //______________________________________________________________________________ 265 Sequence<OUString> CanvasFactory::getAvailableServiceNames() 266 throw (RuntimeException) 267 { 268 Sequence<OUString> aServiceNames(m_aAvailableImplementations.size()); 269 std::transform(m_aAvailableImplementations.begin(), 270 m_aAvailableImplementations.end(), 271 aServiceNames.getArray(), 272 std::select1st<AvailPair>()); 273 return aServiceNames; 274 } 275 276 //______________________________________________________________________________ 277 Reference<XInterface> CanvasFactory::createInstanceWithContext( 278 OUString const & name, Reference<XComponentContext> const & xContext ) 279 throw (Exception) 280 { 281 return createInstanceWithArgumentsAndContext( 282 name, Sequence<Any>(), xContext ); 283 } 284 285 //______________________________________________________________________________ 286 Reference<XInterface> CanvasFactory::use( 287 OUString const & serviceName, 288 Sequence<Any> const & args, 289 Reference<XComponentContext> const & xContext ) const 290 { 291 try { 292 return m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext( 293 serviceName, args, xContext); 294 } 295 catch (RuntimeException &) 296 { 297 throw; 298 } 299 catch (Exception &) 300 { 301 return Reference<XInterface>(); 302 } 303 } 304 305 //______________________________________________________________________________ 306 void CanvasFactory::checkConfigFlag( bool& r_bFlag, 307 bool& r_CacheFlag, 308 const OUString& nodeName ) const 309 { 310 if( m_xCanvasConfigNameAccess.is() ) 311 { 312 m_xCanvasConfigNameAccess->getByName( nodeName ) >>= r_bFlag; 313 314 if( r_CacheFlag != r_bFlag ) 315 { 316 // cache is invalid, because of different order of 317 // elements 318 r_CacheFlag = r_bFlag; 319 m_aCachedImplementations.clear(); 320 } 321 } 322 } 323 324 //______________________________________________________________________________ 325 Reference<XInterface> CanvasFactory::lookupAndUse( 326 OUString const & serviceName, Sequence<Any> const & args, 327 Reference<XComponentContext> const & xContext ) const 328 { 329 ::osl::MutexGuard guard(m_mutex); 330 331 // forcing last entry from impl list, if config flag set 332 bool bForceLastEntry(false); 333 checkConfigFlag( bForceLastEntry, 334 m_bCacheHasForcedLastImpl, 335 OUSTR("ForceSafeServiceImpl") ); 336 337 // use anti-aliasing canvas, if config flag set (or not existing) 338 bool bUseAAEntry(true); 339 checkConfigFlag( bUseAAEntry, 340 m_bCacheHasUseAAEntry, 341 OUSTR("UseAntialiasingCanvas") ); 342 343 // use accelerated canvas, if config flag set (or not existing) 344 bool bUseAcceleratedEntry(true); 345 checkConfigFlag( bUseAcceleratedEntry, 346 m_bCacheHasUseAcceleratedEntry, 347 OUSTR("UseAcceleratedCanvas") ); 348 349 // try to reuse last working implementation for given service name 350 const CacheVector::iterator aEnd(m_aCachedImplementations.end()); 351 CacheVector::iterator aMatch; 352 if( (aMatch=std::find_if(m_aCachedImplementations.begin(), 353 aEnd, 354 boost::bind(&OUString::equals, 355 boost::cref(serviceName), 356 boost::bind( 357 std::select1st<CachePair>(), 358 _1)))) != aEnd ) 359 { 360 Reference<XInterface> xCanvas( use( aMatch->second, args, xContext ) ); 361 if(xCanvas.is()) 362 return xCanvas; 363 } 364 365 // lookup in available service list 366 const AvailVector::const_iterator aAvailEnd(m_aAvailableImplementations.end()); 367 AvailVector::const_iterator aAvailImplsMatch; 368 if( (aAvailImplsMatch=std::find_if(m_aAvailableImplementations.begin(), 369 aAvailEnd, 370 boost::bind(&OUString::equals, 371 boost::cref(serviceName), 372 boost::bind( 373 std::select1st<AvailPair>(), 374 _1)))) == aAvailEnd ) 375 { 376 return Reference<XInterface>(); 377 } 378 379 const AvailVector::const_iterator aAAEnd(m_aAAImplementations.end()); 380 AvailVector::const_iterator aAAImplsMatch; 381 if( (aAAImplsMatch=std::find_if(m_aAAImplementations.begin(), 382 aAAEnd, 383 boost::bind(&OUString::equals, 384 boost::cref(serviceName), 385 boost::bind( 386 std::select1st<AvailPair>(), 387 _1)))) == aAAEnd ) 388 { 389 return Reference<XInterface>(); 390 } 391 392 const AvailVector::const_iterator aAccelEnd(m_aAcceleratedImplementations.end()); 393 AvailVector::const_iterator aAccelImplsMatch; 394 if( (aAccelImplsMatch=std::find_if(m_aAcceleratedImplementations.begin(), 395 aAccelEnd, 396 boost::bind(&OUString::equals, 397 boost::cref(serviceName), 398 boost::bind( 399 std::select1st<AvailPair>(), 400 _1)))) == aAccelEnd ) 401 { 402 return Reference<XInterface>(); 403 } 404 405 const Sequence<OUString> aPreferredImpls( aAvailImplsMatch->second ); 406 const OUString* pCurrImpl = aPreferredImpls.getConstArray(); 407 const OUString* const pEndImpl = pCurrImpl + aPreferredImpls.getLength(); 408 409 const Sequence<OUString> aAAImpls( aAAImplsMatch->second ); 410 const OUString* const pFirstAAImpl = aAAImpls.getConstArray(); 411 const OUString* const pEndAAImpl = pFirstAAImpl + aAAImpls.getLength(); 412 413 const Sequence<OUString> aAccelImpls( aAccelImplsMatch->second ); 414 const OUString* const pFirstAccelImpl = aAccelImpls.getConstArray(); 415 const OUString* const pEndAccelImpl = pFirstAccelImpl + aAccelImpls.getLength(); 416 417 // force last entry from impl list, if config flag set 418 if( bForceLastEntry ) 419 pCurrImpl = pEndImpl-1; 420 421 while( pCurrImpl != pEndImpl ) 422 { 423 const OUString aCurrName(pCurrImpl->trim()); 424 425 // check whether given canvas service is listed in the 426 // sequence of "accelerated canvas implementations" 427 const bool bIsAcceleratedImpl( 428 std::find_if(pFirstAccelImpl, 429 pEndAccelImpl, 430 boost::bind(&OUString::equals, 431 boost::cref(aCurrName), 432 boost::bind( 433 &OUString::trim, 434 _1))) != pEndAccelImpl ); 435 436 // check whether given canvas service is listed in the 437 // sequence of "antialiasing canvas implementations" 438 const bool bIsAAImpl( 439 std::find_if(pFirstAAImpl, 440 pEndAAImpl, 441 boost::bind(&OUString::equals, 442 boost::cref(aCurrName), 443 boost::bind( 444 &OUString::trim, 445 _1))) != pEndAAImpl ); 446 447 // try to instantiate canvas *only* if either accel and AA 448 // property match preference, *or*, if there's a mismatch, only 449 // go for a less capable canvas (that effectively let those 450 // pour canvas impls still work as fallbacks, should an 451 // accelerated/AA one fail). Property implies configuration: 452 // http://en.wikipedia.org/wiki/Truth_table#Logical_implication 453 if( (!bIsAAImpl || bUseAAEntry) && (!bIsAcceleratedImpl || bUseAcceleratedEntry) ) 454 { 455 Reference<XInterface> xCanvas( 456 use( pCurrImpl->trim(), args, xContext ) ); 457 458 if(xCanvas.is()) 459 { 460 if( aMatch != aEnd ) 461 { 462 // cache entry exists, replace dysfunctional 463 // implementation name 464 aMatch->second = pCurrImpl->trim(); 465 } 466 else 467 { 468 // new service name, add new cache entry 469 m_aCachedImplementations.push_back(std::make_pair(serviceName, 470 pCurrImpl->trim())); 471 } 472 473 return xCanvas; 474 } 475 } 476 477 ++pCurrImpl; 478 } 479 480 return Reference<XInterface>(); 481 } 482 483 //______________________________________________________________________________ 484 Reference<XInterface> CanvasFactory::createInstanceWithArgumentsAndContext( 485 OUString const & preferredOne, Sequence<Any> const & args, 486 Reference<XComponentContext> const & xContext ) throw (Exception) 487 { 488 Reference<XInterface> xCanvas( 489 lookupAndUse( preferredOne, args, xContext ) ); 490 if(xCanvas.is()) 491 return xCanvas; 492 493 // last resort: try service name directly 494 return use( preferredOne, args, xContext ); 495 } 496 497 // XMultiServiceFactory 498 //______________________________________________________________________________ 499 Reference<XInterface> CanvasFactory::createInstance( OUString const & name ) 500 throw (Exception) 501 { 502 return createInstanceWithArgumentsAndContext( 503 name, Sequence<Any>(), m_xContext ); 504 } 505 506 //______________________________________________________________________________ 507 Reference<XInterface> CanvasFactory::createInstanceWithArguments( 508 OUString const & name, Sequence<Any> const & args ) throw (Exception) 509 { 510 return createInstanceWithArgumentsAndContext( 511 name, args, m_xContext ); 512 } 513 514 const ::cppu::ImplementationEntry s_entries [] = { 515 { 516 create, 517 getImplName, 518 getSuppServices, 519 ::cppu::createSingleComponentFactory, 520 0, 0 521 }, 522 { 0, 0, 0, 0, 0, 0 } 523 }; 524 525 } // anon namespace 526 527 extern "C" { 528 529 void SAL_CALL component_getImplementationEnvironment( 530 const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) 531 { 532 *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; 533 } 534 535 void * SAL_CALL component_getFactory( 536 sal_Char const * pImplName, 537 lang::XMultiServiceFactory * pServiceManager, 538 registry::XRegistryKey * pRegistryKey ) 539 { 540 return ::cppu::component_getFactoryHelper( 541 pImplName, pServiceManager, pRegistryKey, s_entries ); 542 } 543 544 } 545 546