LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / canvas / source / factory / cf_service.cxx
blob6cb27699864c152ac3d28c85e4557dc4543d4159
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 <mutex>
25 #include <utility>
26 #include <vector>
28 #include <com/sun/star/configuration/theDefaultProvider.hpp>
29 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
30 #include <com/sun/star/container/XNameAccess.hpp>
31 #include <com/sun/star/lang/IllegalArgumentException.hpp>
32 #include <com/sun/star/lang/XServiceInfo.hpp>
33 #include <com/sun/star/lang/XServiceName.hpp>
34 #include <com/sun/star/uno/XComponentContext.hpp>
35 #include <comphelper/propertysequence.hxx>
36 #include <cppuhelper/implbase.hxx>
37 #include <cppuhelper/supportsservice.hxx>
38 #include <o3tl/functional.hxx>
39 #include <config_features.h>
40 #include <vcl/skia/SkiaHelper.hxx>
41 #include <unotools/configmgr.hxx>
43 using namespace ::com::sun::star;
44 using namespace ::com::sun::star::uno;
47 namespace
50 class CanvasFactory
51 : public ::cppu::WeakImplHelper< lang::XServiceInfo,
52 lang::XMultiComponentFactory,
53 lang::XMultiServiceFactory >
55 typedef std::pair< OUString, Sequence< OUString > > AvailPair;
56 typedef std::pair< OUString, OUString > CachePair;
57 typedef std::vector< AvailPair > AvailVector;
58 typedef std::vector< CachePair > CacheVector;
61 mutable std::mutex m_mutex;
62 Reference<XComponentContext> m_xContext;
63 Reference<container::XNameAccess> m_xCanvasConfigNameAccess;
64 AvailVector m_aAvailableImplementations;
65 AvailVector m_aAcceleratedImplementations;
66 AvailVector m_aAAImplementations;
67 mutable CacheVector m_aCachedImplementations;
68 mutable bool m_bCacheHasForcedLastImpl;
69 mutable bool m_bCacheHasUseAcceleratedEntry;
70 mutable bool m_bCacheHasUseAAEntry;
72 void checkConfigFlag( bool& r_bFlag,
73 bool& r_CacheFlag,
74 const OUString& nodeName ) const;
75 Reference<XInterface> use(
76 OUString const & serviceName,
77 Sequence<Any> const & args,
78 Reference<XComponentContext> const & xContext ) const;
79 Reference<XInterface> lookupAndUse(
80 OUString const & serviceName, Sequence<Any> const & args,
81 Reference<XComponentContext> const & xContext ) const;
83 public:
84 virtual ~CanvasFactory() override;
85 explicit CanvasFactory( Reference<XComponentContext> const & xContext );
87 // XServiceInfo
88 virtual OUString SAL_CALL getImplementationName() override;
89 virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) override;
90 virtual Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
92 // XMultiComponentFactory
93 virtual Sequence<OUString> SAL_CALL getAvailableServiceNames() override;
94 virtual Reference<XInterface> SAL_CALL createInstanceWithContext(
95 OUString const & name,
96 Reference<XComponentContext> const & xContext ) override;
97 virtual Reference<XInterface> SAL_CALL
98 createInstanceWithArgumentsAndContext(
99 OUString const & name,
100 Sequence<Any> const & args,
101 Reference<XComponentContext> const & xContext ) override;
103 // XMultiServiceFactory
104 virtual Reference<XInterface> SAL_CALL createInstance(
105 OUString const & name ) override;
106 virtual Reference<XInterface> SAL_CALL createInstanceWithArguments(
107 OUString const & name, Sequence<Any> const & args ) override;
110 CanvasFactory::CanvasFactory( Reference<XComponentContext> const & xContext ) :
111 m_xContext(xContext),
112 m_bCacheHasForcedLastImpl(),
113 m_bCacheHasUseAcceleratedEntry(),
114 m_bCacheHasUseAAEntry()
116 if (!utl::ConfigManager::IsFuzzing())
120 // read out configuration for preferred services:
121 Reference<lang::XMultiServiceFactory> xConfigProvider(
122 configuration::theDefaultProvider::get( m_xContext ) );
124 uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
126 {"nodepath", uno::Any(OUString("/org.openoffice.Office.Canvas"))}
127 }));
128 m_xCanvasConfigNameAccess.set(
129 xConfigProvider->createInstanceWithArguments(
130 "com.sun.star.configuration.ConfigurationAccess",
131 aArgs ),
132 UNO_QUERY_THROW );
134 uno::Sequence<uno::Any> aArgs2(comphelper::InitAnyPropertySequence(
136 {"nodepath", uno::Any(OUString("/org.openoffice.Office.Canvas/CanvasServiceList"))}
137 }));
138 Reference<container::XNameAccess> xNameAccess(
139 xConfigProvider->createInstanceWithArguments(
140 "com.sun.star.configuration.ConfigurationAccess",
141 aArgs2 ), UNO_QUERY_THROW );
142 Reference<container::XHierarchicalNameAccess> xHierarchicalNameAccess(
143 xNameAccess, UNO_QUERY_THROW);
145 Sequence<OUString> serviceNames = xNameAccess->getElementNames();
146 const OUString* pCurr = serviceNames.getConstArray();
147 const OUString* const pEnd = pCurr + serviceNames.getLength();
148 while( pCurr != pEnd )
150 Reference<container::XNameAccess> xEntryNameAccess(
151 xHierarchicalNameAccess->getByHierarchicalName(*pCurr),
152 UNO_QUERY );
154 if( xEntryNameAccess.is() )
156 Sequence<OUString> implementationList;
157 if( xEntryNameAccess->getByName("PreferredImplementations") >>= implementationList )
159 m_aAvailableImplementations.emplace_back(*pCurr,implementationList );
161 if( xEntryNameAccess->getByName("AcceleratedImplementations") >>= implementationList )
163 m_aAcceleratedImplementations.emplace_back(*pCurr,implementationList );
165 if( xEntryNameAccess->getByName("AntialiasingImplementations") >>= implementationList )
167 m_aAAImplementations.emplace_back(*pCurr,implementationList );
172 ++pCurr;
175 catch (const RuntimeException &)
177 throw;
179 catch (const Exception&)
184 if (m_aAvailableImplementations.empty())
186 // Ugh. Looks like configuration is borked. Fake minimal
187 // setup.
188 m_aAvailableImplementations.emplace_back(OUString("com.sun.star.rendering.Canvas"),
189 Sequence<OUString>{ "com.sun.star.comp.rendering.Canvas.VCL" } );
191 m_aAvailableImplementations.emplace_back(OUString("com.sun.star.rendering.SpriteCanvas"),
192 Sequence<OUString>{ "com.sun.star.comp.rendering.SpriteCanvas.VCL" } );
196 CanvasFactory::~CanvasFactory()
201 // XServiceInfo
202 OUString CanvasFactory::getImplementationName()
204 return "com.sun.star.comp.rendering.CanvasFactory";
207 sal_Bool CanvasFactory::supportsService( OUString const & serviceName )
209 return cppu::supportsService(this, serviceName);
212 Sequence<OUString> CanvasFactory::getSupportedServiceNames()
214 return { "com.sun.star.rendering.CanvasFactory" };
217 // XMultiComponentFactory
218 Sequence<OUString> CanvasFactory::getAvailableServiceNames()
220 Sequence<OUString> aServiceNames(m_aAvailableImplementations.size());
221 std::transform(m_aAvailableImplementations.begin(),
222 m_aAvailableImplementations.end(),
223 aServiceNames.getArray(),
224 o3tl::select1st< AvailPair >());
225 return aServiceNames;
228 Reference<XInterface> CanvasFactory::createInstanceWithContext(
229 OUString const & name, Reference<XComponentContext> const & xContext )
231 return createInstanceWithArgumentsAndContext(
232 name, Sequence<Any>(), xContext );
236 Reference<XInterface> CanvasFactory::use(
237 OUString const & serviceName,
238 Sequence<Any> const & args,
239 Reference<XComponentContext> const & xContext ) const
241 try {
242 return m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
243 serviceName, args, xContext);
245 catch (css::lang::IllegalArgumentException &)
247 return Reference<XInterface>();
249 catch (const RuntimeException &)
251 throw;
253 catch (const Exception &)
255 return Reference<XInterface>();
260 void CanvasFactory::checkConfigFlag( bool& r_bFlag,
261 bool& r_CacheFlag,
262 const OUString& nodeName ) const
264 if( m_xCanvasConfigNameAccess.is() )
266 m_xCanvasConfigNameAccess->getByName( nodeName ) >>= r_bFlag;
268 if( r_CacheFlag != r_bFlag )
270 // cache is invalid, because of different order of
271 // elements
272 r_CacheFlag = r_bFlag;
273 m_aCachedImplementations.clear();
279 Reference<XInterface> CanvasFactory::lookupAndUse(
280 OUString const & serviceName, Sequence<Any> const & args,
281 Reference<XComponentContext> const & xContext ) const
283 std::scoped_lock guard(m_mutex);
285 // forcing last entry from impl list, if config flag set
286 bool bForceLastEntry(false);
287 checkConfigFlag( bForceLastEntry,
288 m_bCacheHasForcedLastImpl,
289 "ForceSafeServiceImpl" );
291 // use anti-aliasing canvas, if config flag set (or not existing)
292 bool bUseAAEntry(true);
293 checkConfigFlag( bUseAAEntry,
294 m_bCacheHasUseAAEntry,
295 "UseAntialiasingCanvas" );
297 // use accelerated canvas, if config flag set (or not existing)
298 bool bUseAcceleratedEntry(true);
299 checkConfigFlag( bUseAcceleratedEntry,
300 m_bCacheHasUseAcceleratedEntry,
301 "UseAcceleratedCanvas" );
303 // try to reuse last working implementation for given service name
304 const CacheVector::iterator aEnd(m_aCachedImplementations.end());
305 auto aMatch = std::find_if(
306 m_aCachedImplementations.begin(),
307 aEnd,
308 [&serviceName](CachePair const& cp)
309 { return serviceName == cp.first; }
311 if( aMatch != aEnd ) {
312 Reference<XInterface> xCanvas( use( aMatch->second, args, xContext ) );
313 if(xCanvas.is())
314 return xCanvas;
317 // lookup in available service list
318 const AvailVector::const_iterator aAvailEnd(m_aAvailableImplementations.end());
319 auto aAvailImplsMatch = std::find_if(
320 m_aAvailableImplementations.begin(),
321 aAvailEnd,
322 [&serviceName](AvailPair const& ap)
323 { return serviceName == ap.first; }
325 if( aAvailImplsMatch == aAvailEnd ) {
326 return Reference<XInterface>();
329 const AvailVector::const_iterator aAAEnd(m_aAAImplementations.end());
330 auto aAAImplsMatch = std::find_if(
331 m_aAAImplementations.begin(),
332 aAAEnd,
333 [&serviceName](AvailPair const& ap)
334 { return serviceName == ap.first; }
336 if( aAAImplsMatch == aAAEnd ) {
337 return Reference<XInterface>();
340 const AvailVector::const_iterator aAccelEnd(m_aAcceleratedImplementations.end());
341 auto aAccelImplsMatch = std::find_if(
342 m_aAcceleratedImplementations.begin(),
343 aAccelEnd,
344 [&serviceName](AvailPair const& ap)
345 { return serviceName == ap.first; }
347 if( aAccelImplsMatch == aAccelEnd ) {
348 return Reference<XInterface>();
351 const Sequence<OUString> aPreferredImpls( aAvailImplsMatch->second );
352 const OUString* pCurrImpl = aPreferredImpls.begin();
353 const OUString* const pEndImpl = aPreferredImpls.end();
355 const Sequence<OUString> aAAImpls( aAAImplsMatch->second );
357 const Sequence<OUString> aAccelImpls( aAccelImplsMatch->second );
359 // force last entry from impl list, if config flag set
360 if (bForceLastEntry && pCurrImpl != pEndImpl)
361 pCurrImpl = pEndImpl-1;
363 for(; pCurrImpl != pEndImpl; ++pCurrImpl)
365 const OUString aCurrName(pCurrImpl->trim());
367 // Skia works only with vclcanvas.
368 if( SkiaHelper::isVCLSkiaEnabled() && !aCurrName.endsWith(".VCL"))
369 continue;
371 // check whether given canvas service is listed in the
372 // sequence of "accelerated canvas implementations"
373 const bool bIsAcceleratedImpl(
374 std::any_of(aAccelImpls.begin(), aAccelImpls.end(),
375 [&aCurrName](OUString const& src)
376 { return aCurrName == src.trim(); }
379 // check whether given canvas service is listed in the
380 // sequence of "antialiasing canvas implementations"
381 const bool bIsAAImpl(
382 std::any_of(aAAImpls.begin(), aAAImpls.end(),
383 [&aCurrName](OUString const& src)
384 { return aCurrName == src.trim(); }
387 // try to instantiate canvas *only* if either accel and AA
388 // property match preference, *or*, if there's a mismatch, only
389 // go for a less capable canvas (that effectively let those
390 // pour canvas impls still work as fallbacks, should an
391 // accelerated/AA one fail). Property implies configuration:
392 // http://en.wikipedia.org/wiki/Truth_table#Logical_implication
393 if( (!bIsAAImpl || bUseAAEntry) && (!bIsAcceleratedImpl || bUseAcceleratedEntry) )
395 Reference<XInterface> xCanvas(use(aCurrName, args, xContext));
397 if(xCanvas.is())
399 if( aMatch != aEnd )
401 // cache entry exists, replace dysfunctional
402 // implementation name
403 aMatch->second = aCurrName;
405 else
407 // new service name, add new cache entry
408 m_aCachedImplementations.emplace_back(serviceName, aCurrName);
411 return xCanvas;
416 return Reference<XInterface>();
420 Reference<XInterface> CanvasFactory::createInstanceWithArgumentsAndContext(
421 OUString const & preferredOne, Sequence<Any> const & args,
422 Reference<XComponentContext> const & xContext )
424 Reference<XInterface> xCanvas(lookupAndUse(preferredOne, args, xContext));
425 if (!xCanvas.is())
426 // last resort: try service name directly
427 xCanvas = use(preferredOne, args, xContext);
429 if (xCanvas.is())
431 Reference<lang::XServiceName> xServiceName(xCanvas, uno::UNO_QUERY);
432 SAL_INFO("canvas", "using " << (xServiceName.is() ? xServiceName->getServiceName()
433 : OUString("(unknown)")));
435 return xCanvas;
438 // XMultiServiceFactory
440 Reference<XInterface> CanvasFactory::createInstance( OUString const & name )
442 return createInstanceWithArgumentsAndContext(
443 name, Sequence<Any>(), m_xContext );
447 Reference<XInterface> CanvasFactory::createInstanceWithArguments(
448 OUString const & name, Sequence<Any> const & args )
450 return createInstanceWithArgumentsAndContext(
451 name, args, m_xContext );
454 } // anon namespace
457 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
458 com_sun_star_comp_rendering_CanvasFactory_get_implementation(css::uno::XComponentContext* context,
459 css::uno::Sequence<css::uno::Any> const &)
461 return cppu::acquire(new CanvasFactory(context));
465 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */