nss: upgrade to release 3.73
[LibreOffice.git] / canvas / source / factory / cf_service.cxx
blob9bb75d5e26b00bffe43c6bcbe645a5641c64e82a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <algorithm>
24 #include <utility>
25 #include <vector>
27 #include <com/sun/star/configuration/theDefaultProvider.hpp>
28 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
29 #include <com/sun/star/container/XNameAccess.hpp>
30 #include <com/sun/star/lang/IllegalArgumentException.hpp>
31 #include <com/sun/star/lang/XServiceInfo.hpp>
32 #include <com/sun/star/lang/XServiceName.hpp>
33 #include <com/sun/star/uno/XComponentContext.hpp>
34 #include <comphelper/propertysequence.hxx>
35 #include <cppuhelper/implbase.hxx>
36 #include <cppuhelper/supportsservice.hxx>
37 #include <osl/mutex.hxx>
38 #include <o3tl/functional.hxx>
39 #include <config_features.h>
40 #if HAVE_FEATURE_OPENGL
41 #include <vcl/opengl/OpenGLWrapper.hxx>
42 #endif
43 #include <vcl/skia/SkiaHelper.hxx>
44 #include <unotools/configmgr.hxx>
46 using namespace ::com::sun::star;
47 using namespace ::com::sun::star::uno;
50 namespace
53 class CanvasFactory
54 : public ::cppu::WeakImplHelper< lang::XServiceInfo,
55 lang::XMultiComponentFactory,
56 lang::XMultiServiceFactory >
58 typedef std::pair< OUString, Sequence< OUString > > AvailPair;
59 typedef std::pair< OUString, OUString > CachePair;
60 typedef std::vector< AvailPair > AvailVector;
61 typedef std::vector< CachePair > CacheVector;
64 mutable ::osl::Mutex m_mutex;
65 Reference<XComponentContext> m_xContext;
66 Reference<container::XNameAccess> m_xCanvasConfigNameAccess;
67 AvailVector m_aAvailableImplementations;
68 AvailVector m_aAcceleratedImplementations;
69 AvailVector m_aAAImplementations;
70 mutable CacheVector m_aCachedImplementations;
71 mutable bool m_bCacheHasForcedLastImpl;
72 mutable bool m_bCacheHasUseAcceleratedEntry;
73 mutable bool m_bCacheHasUseAAEntry;
75 void checkConfigFlag( bool& r_bFlag,
76 bool& r_CacheFlag,
77 const OUString& nodeName ) const;
78 Reference<XInterface> use(
79 OUString const & serviceName,
80 Sequence<Any> const & args,
81 Reference<XComponentContext> const & xContext ) const;
82 Reference<XInterface> lookupAndUse(
83 OUString const & serviceName, Sequence<Any> const & args,
84 Reference<XComponentContext> const & xContext ) const;
86 public:
87 virtual ~CanvasFactory() override;
88 explicit CanvasFactory( Reference<XComponentContext> const & xContext );
90 // XServiceInfo
91 virtual OUString SAL_CALL getImplementationName() override;
92 virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) override;
93 virtual Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
95 // XMultiComponentFactory
96 virtual Sequence<OUString> SAL_CALL getAvailableServiceNames() override;
97 virtual Reference<XInterface> SAL_CALL createInstanceWithContext(
98 OUString const & name,
99 Reference<XComponentContext> const & xContext ) override;
100 virtual Reference<XInterface> SAL_CALL
101 createInstanceWithArgumentsAndContext(
102 OUString const & name,
103 Sequence<Any> const & args,
104 Reference<XComponentContext> const & xContext ) override;
106 // XMultiServiceFactory
107 virtual Reference<XInterface> SAL_CALL createInstance(
108 OUString const & name ) override;
109 virtual Reference<XInterface> SAL_CALL createInstanceWithArguments(
110 OUString const & name, Sequence<Any> const & args ) override;
113 CanvasFactory::CanvasFactory( Reference<XComponentContext> const & xContext ) :
114 m_mutex(),
115 m_xContext(xContext),
116 m_xCanvasConfigNameAccess(),
117 m_aAvailableImplementations(),
118 m_aAcceleratedImplementations(),
119 m_aAAImplementations(),
120 m_aCachedImplementations(),
121 m_bCacheHasForcedLastImpl(),
122 m_bCacheHasUseAcceleratedEntry(),
123 m_bCacheHasUseAAEntry()
125 if (!utl::ConfigManager::IsFuzzing())
129 // read out configuration for preferred services:
130 Reference<lang::XMultiServiceFactory> xConfigProvider(
131 configuration::theDefaultProvider::get( m_xContext ) );
133 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
135 {"nodepath", uno::Any(OUString("/org.openoffice.Office.Canvas"))}
136 }));
137 m_xCanvasConfigNameAccess.set(
138 xConfigProvider->createInstanceWithArguments(
139 "com.sun.star.configuration.ConfigurationAccess",
140 aArgs ),
141 UNO_QUERY_THROW );
143 uno::Sequence<uno::Any> aArgs2(comphelper::InitAnyPropertySequence(
145 {"nodepath", uno::Any(OUString("/org.openoffice.Office.Canvas/CanvasServiceList"))}
146 }));
147 Reference<container::XNameAccess> xNameAccess(
148 xConfigProvider->createInstanceWithArguments(
149 "com.sun.star.configuration.ConfigurationAccess",
150 aArgs2 ), UNO_QUERY_THROW );
151 Reference<container::XHierarchicalNameAccess> xHierarchicalNameAccess(
152 xNameAccess, UNO_QUERY_THROW);
154 Sequence<OUString> serviceNames = xNameAccess->getElementNames();
155 const OUString* pCurr = serviceNames.getConstArray();
156 const OUString* const pEnd = pCurr + serviceNames.getLength();
157 while( pCurr != pEnd )
159 Reference<container::XNameAccess> xEntryNameAccess(
160 xHierarchicalNameAccess->getByHierarchicalName(*pCurr),
161 UNO_QUERY );
163 if( xEntryNameAccess.is() )
165 Sequence<OUString> implementationList;
166 if( xEntryNameAccess->getByName("PreferredImplementations") >>= implementationList )
168 m_aAvailableImplementations.emplace_back(*pCurr,implementationList );
170 if( xEntryNameAccess->getByName("AcceleratedImplementations") >>= implementationList )
172 m_aAcceleratedImplementations.emplace_back(*pCurr,implementationList );
174 if( xEntryNameAccess->getByName("AntialiasingImplementations") >>= implementationList )
176 m_aAAImplementations.emplace_back(*pCurr,implementationList );
181 ++pCurr;
184 catch (const RuntimeException &)
186 throw;
188 catch (const Exception&)
193 if (m_aAvailableImplementations.empty())
195 // Ugh. Looks like configuration is borked. Fake minimal
196 // setup.
197 Sequence<OUString> aServices { "com.sun.star.comp.rendering.Canvas.VCL" };
198 m_aAvailableImplementations.emplace_back(OUString("com.sun.star.rendering.Canvas"),
199 aServices );
201 aServices[0] = "com.sun.star.comp.rendering.SpriteCanvas.VCL";
202 m_aAvailableImplementations.emplace_back(OUString("com.sun.star.rendering.SpriteCanvas"),
203 aServices );
207 CanvasFactory::~CanvasFactory()
212 // XServiceInfo
213 OUString CanvasFactory::getImplementationName()
215 return "com.sun.star.comp.rendering.CanvasFactory";
218 sal_Bool CanvasFactory::supportsService( OUString const & serviceName )
220 return cppu::supportsService(this, serviceName);
223 Sequence<OUString> CanvasFactory::getSupportedServiceNames()
225 return { "com.sun.star.rendering.CanvasFactory" };
228 // XMultiComponentFactory
229 Sequence<OUString> CanvasFactory::getAvailableServiceNames()
231 Sequence<OUString> aServiceNames(m_aAvailableImplementations.size());
232 std::transform(m_aAvailableImplementations.begin(),
233 m_aAvailableImplementations.end(),
234 aServiceNames.getArray(),
235 o3tl::select1st< AvailPair >());
236 return aServiceNames;
239 Reference<XInterface> CanvasFactory::createInstanceWithContext(
240 OUString const & name, Reference<XComponentContext> const & xContext )
242 return createInstanceWithArgumentsAndContext(
243 name, Sequence<Any>(), xContext );
247 Reference<XInterface> CanvasFactory::use(
248 OUString const & serviceName,
249 Sequence<Any> const & args,
250 Reference<XComponentContext> const & xContext ) const
252 try {
253 return m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
254 serviceName, args, xContext);
256 catch (css::lang::IllegalArgumentException &)
258 return Reference<XInterface>();
260 catch (const RuntimeException &)
262 throw;
264 catch (const Exception &)
266 return Reference<XInterface>();
271 void CanvasFactory::checkConfigFlag( bool& r_bFlag,
272 bool& r_CacheFlag,
273 const OUString& nodeName ) const
275 if( m_xCanvasConfigNameAccess.is() )
277 m_xCanvasConfigNameAccess->getByName( nodeName ) >>= r_bFlag;
279 if( r_CacheFlag != r_bFlag )
281 // cache is invalid, because of different order of
282 // elements
283 r_CacheFlag = r_bFlag;
284 m_aCachedImplementations.clear();
290 Reference<XInterface> CanvasFactory::lookupAndUse(
291 OUString const & serviceName, Sequence<Any> const & args,
292 Reference<XComponentContext> const & xContext ) const
294 ::osl::MutexGuard guard(m_mutex);
296 // forcing last entry from impl list, if config flag set
297 bool bForceLastEntry(false);
298 checkConfigFlag( bForceLastEntry,
299 m_bCacheHasForcedLastImpl,
300 "ForceSafeServiceImpl" );
302 // tdf#93870 - force VCL canvas in OpenGL mode for now.
303 #if HAVE_FEATURE_OPENGL
304 if( OpenGLWrapper::isVCLOpenGLEnabled() )
305 bForceLastEntry = true;
306 #endif
308 // use anti-aliasing canvas, if config flag set (or not existing)
309 bool bUseAAEntry(true);
310 checkConfigFlag( bUseAAEntry,
311 m_bCacheHasUseAAEntry,
312 "UseAntialiasingCanvas" );
314 // use accelerated canvas, if config flag set (or not existing)
315 bool bUseAcceleratedEntry(true);
316 checkConfigFlag( bUseAcceleratedEntry,
317 m_bCacheHasUseAcceleratedEntry,
318 "UseAcceleratedCanvas" );
320 // try to reuse last working implementation for given service name
321 const CacheVector::iterator aEnd(m_aCachedImplementations.end());
322 auto aMatch = std::find_if(
323 m_aCachedImplementations.begin(),
324 aEnd,
325 [&serviceName](CachePair const& cp)
326 { return serviceName == cp.first; }
328 if( aMatch != aEnd ) {
329 Reference<XInterface> xCanvas( use( aMatch->second, args, xContext ) );
330 if(xCanvas.is())
331 return xCanvas;
334 // lookup in available service list
335 const AvailVector::const_iterator aAvailEnd(m_aAvailableImplementations.end());
336 auto aAvailImplsMatch = std::find_if(
337 m_aAvailableImplementations.begin(),
338 aAvailEnd,
339 [&serviceName](AvailPair const& ap)
340 { return serviceName == ap.first; }
342 if( aAvailImplsMatch == aAvailEnd ) {
343 return Reference<XInterface>();
346 const AvailVector::const_iterator aAAEnd(m_aAAImplementations.end());
347 auto aAAImplsMatch = std::find_if(
348 m_aAAImplementations.begin(),
349 aAAEnd,
350 [&serviceName](AvailPair const& ap)
351 { return serviceName == ap.first; }
353 if( aAAImplsMatch == aAAEnd ) {
354 return Reference<XInterface>();
357 const AvailVector::const_iterator aAccelEnd(m_aAcceleratedImplementations.end());
358 auto aAccelImplsMatch = std::find_if(
359 m_aAcceleratedImplementations.begin(),
360 aAccelEnd,
361 [&serviceName](AvailPair const& ap)
362 { return serviceName == ap.first; }
364 if( aAccelImplsMatch == aAccelEnd ) {
365 return Reference<XInterface>();
368 const Sequence<OUString> aPreferredImpls( aAvailImplsMatch->second );
369 const OUString* pCurrImpl = aPreferredImpls.begin();
370 const OUString* const pEndImpl = aPreferredImpls.end();
372 const Sequence<OUString> aAAImpls( aAAImplsMatch->second );
374 const Sequence<OUString> aAccelImpls( aAccelImplsMatch->second );
376 // force last entry from impl list, if config flag set
377 if (bForceLastEntry && pCurrImpl != pEndImpl)
378 pCurrImpl = pEndImpl-1;
380 for(; pCurrImpl != pEndImpl; ++pCurrImpl)
382 const OUString aCurrName(pCurrImpl->trim());
384 // Skia works only with vclcanvas.
385 if( SkiaHelper::isVCLSkiaEnabled() && !aCurrName.endsWith(".VCL"))
386 continue;
388 // check whether given canvas service is listed in the
389 // sequence of "accelerated canvas implementations"
390 const bool bIsAcceleratedImpl(
391 std::any_of(aAccelImpls.begin(), aAccelImpls.end(),
392 [&aCurrName](OUString const& src)
393 { return aCurrName == src.trim(); }
396 // check whether given canvas service is listed in the
397 // sequence of "antialiasing canvas implementations"
398 const bool bIsAAImpl(
399 std::any_of(aAAImpls.begin(), aAAImpls.end(),
400 [&aCurrName](OUString const& src)
401 { return aCurrName == src.trim(); }
404 // try to instantiate canvas *only* if either accel and AA
405 // property match preference, *or*, if there's a mismatch, only
406 // go for a less capable canvas (that effectively let those
407 // pour canvas impls still work as fallbacks, should an
408 // accelerated/AA one fail). Property implies configuration:
409 // http://en.wikipedia.org/wiki/Truth_table#Logical_implication
410 if( (!bIsAAImpl || bUseAAEntry) && (!bIsAcceleratedImpl || bUseAcceleratedEntry) )
412 Reference<XInterface> xCanvas(use(aCurrName, args, xContext));
414 if(xCanvas.is())
416 if( aMatch != aEnd )
418 // cache entry exists, replace dysfunctional
419 // implementation name
420 aMatch->second = aCurrName;
422 else
424 // new service name, add new cache entry
425 m_aCachedImplementations.emplace_back(serviceName, aCurrName);
428 return xCanvas;
433 return Reference<XInterface>();
437 Reference<XInterface> CanvasFactory::createInstanceWithArgumentsAndContext(
438 OUString const & preferredOne, Sequence<Any> const & args,
439 Reference<XComponentContext> const & xContext )
441 Reference<XInterface> xCanvas(lookupAndUse(preferredOne, args, xContext));
442 if (!xCanvas.is())
443 // last resort: try service name directly
444 xCanvas = use(preferredOne, args, xContext);
446 if (xCanvas.is())
448 Reference<lang::XServiceName> xServiceName(xCanvas, uno::UNO_QUERY);
449 SAL_INFO("canvas", "using " << (xServiceName.is() ? xServiceName->getServiceName()
450 : OUString("(unknown)")));
452 return xCanvas;
455 // XMultiServiceFactory
457 Reference<XInterface> CanvasFactory::createInstance( OUString const & name )
459 return createInstanceWithArgumentsAndContext(
460 name, Sequence<Any>(), m_xContext );
464 Reference<XInterface> CanvasFactory::createInstanceWithArguments(
465 OUString const & name, Sequence<Any> const & args )
467 return createInstanceWithArgumentsAndContext(
468 name, args, m_xContext );
471 } // anon namespace
474 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
475 com_sun_star_comp_rendering_CanvasFactory_get_implementation(css::uno::XComponentContext* context,
476 css::uno::Sequence<css::uno::Any> const &)
478 return cppu::acquire(new CanvasFactory(context));
482 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */