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