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