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