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