tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / canvas / source / factory / cf_service.cxx
blob62d7ec3c0bd35209653a046f1737a13c05bc36fe
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 <o3tl/string_view.hxx>
40 #include <vcl/skia/SkiaHelper.hxx>
41 #include <comphelper/configuration.hxx>
42 #include <officecfg/Office/Canvas.hxx>
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
48 namespace
51 class CanvasFactory
52 : public ::cppu::WeakImplHelper< lang::XServiceInfo,
53 lang::XMultiComponentFactory,
54 lang::XMultiServiceFactory >
56 typedef std::pair< OUString, Sequence< OUString > > AvailPair;
57 typedef std::pair< OUString, OUString > CachePair;
58 typedef std::vector< AvailPair > AvailVector;
59 typedef std::vector< CachePair > CacheVector;
62 mutable std::mutex m_mutex;
63 Reference<XComponentContext> m_xContext;
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 bool bCurrentConfigValue ) 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 (!comphelper::IsFuzzing())
120 // read out configuration for preferred services:
122 Reference<container::XNameAccess> xNameAccess = officecfg::Office::Canvas::CanvasServiceList::get();
123 Reference<container::XHierarchicalNameAccess> xHierarchicalNameAccess(
124 xNameAccess, UNO_QUERY_THROW);
127 for (auto& serviceName : xNameAccess->getElementNames())
129 Reference<container::XNameAccess> xEntryNameAccess(
130 xHierarchicalNameAccess->getByHierarchicalName(serviceName),
131 UNO_QUERY );
133 if( xEntryNameAccess.is() )
135 Sequence<OUString> implementationList;
136 if( xEntryNameAccess->getByName(u"PreferredImplementations"_ustr) >>= implementationList )
138 m_aAvailableImplementations.emplace_back(serviceName, implementationList);
140 if( xEntryNameAccess->getByName(u"AcceleratedImplementations"_ustr) >>= implementationList )
142 m_aAcceleratedImplementations.emplace_back(serviceName, implementationList);
144 if( xEntryNameAccess->getByName(u"AntialiasingImplementations"_ustr) >>= implementationList )
146 m_aAAImplementations.emplace_back(serviceName, implementationList);
151 catch (const RuntimeException &)
153 throw;
155 catch (const Exception&)
160 if (m_aAvailableImplementations.empty())
162 // Ugh. Looks like configuration is borked. Fake minimal
163 // setup.
164 m_aAvailableImplementations.emplace_back(u"com.sun.star.rendering.Canvas"_ustr,
165 Sequence<OUString>{ u"com.sun.star.comp.rendering.Canvas.VCL"_ustr } );
167 m_aAvailableImplementations.emplace_back(u"com.sun.star.rendering.SpriteCanvas"_ustr,
168 Sequence<OUString>{ u"com.sun.star.comp.rendering.SpriteCanvas.VCL"_ustr } );
172 CanvasFactory::~CanvasFactory()
177 // XServiceInfo
178 OUString CanvasFactory::getImplementationName()
180 return u"com.sun.star.comp.rendering.CanvasFactory"_ustr;
183 sal_Bool CanvasFactory::supportsService( OUString const & serviceName )
185 return cppu::supportsService(this, serviceName);
188 Sequence<OUString> CanvasFactory::getSupportedServiceNames()
190 return { u"com.sun.star.rendering.CanvasFactory"_ustr };
193 // XMultiComponentFactory
194 Sequence<OUString> CanvasFactory::getAvailableServiceNames()
196 Sequence<OUString> aServiceNames(m_aAvailableImplementations.size());
197 std::transform(m_aAvailableImplementations.begin(),
198 m_aAvailableImplementations.end(),
199 aServiceNames.getArray(),
200 o3tl::select1st< AvailPair >());
201 return aServiceNames;
204 Reference<XInterface> CanvasFactory::createInstanceWithContext(
205 OUString const & name, Reference<XComponentContext> const & xContext )
207 return createInstanceWithArgumentsAndContext(
208 name, Sequence<Any>(), xContext );
212 Reference<XInterface> CanvasFactory::use(
213 OUString const & serviceName,
214 Sequence<Any> const & args,
215 Reference<XComponentContext> const & xContext ) const
217 try {
218 return m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
219 serviceName, args, xContext);
221 catch (css::lang::IllegalArgumentException &)
223 return Reference<XInterface>();
225 catch (const RuntimeException &)
227 throw;
229 catch (const Exception &)
231 return Reference<XInterface>();
236 void CanvasFactory::checkConfigFlag( bool& r_bFlag,
237 bool& r_CacheFlag,
238 bool bCurrentConfigValue ) const
240 r_bFlag = bCurrentConfigValue;
242 if( r_CacheFlag != r_bFlag )
244 // cache is invalid, because of different order of
245 // elements
246 r_CacheFlag = r_bFlag;
247 m_aCachedImplementations.clear();
252 Reference<XInterface> CanvasFactory::lookupAndUse(
253 OUString const & serviceName, Sequence<Any> const & args,
254 Reference<XComponentContext> const & xContext ) const
256 std::scoped_lock guard(m_mutex);
258 // forcing last entry from impl list, if config flag set
259 bool bForceLastEntry(false);
260 checkConfigFlag( bForceLastEntry,
261 m_bCacheHasForcedLastImpl,
262 officecfg::Office::Canvas::ForceSafeServiceImpl::get() );
264 // use anti-aliasing canvas, if config flag set (or not existing)
265 bool bUseAAEntry(true);
266 checkConfigFlag( bUseAAEntry,
267 m_bCacheHasUseAAEntry,
268 officecfg::Office::Canvas::UseAntialiasingCanvas::get() );
270 // use accelerated canvas, if config flag set (or not existing)
271 bool bUseAcceleratedEntry(true);
272 checkConfigFlag( bUseAcceleratedEntry,
273 m_bCacheHasUseAcceleratedEntry,
274 officecfg::Office::Canvas::UseAcceleratedCanvas::get() );
276 // try to reuse last working implementation for given service name
277 const CacheVector::iterator aEnd(m_aCachedImplementations.end());
278 auto aMatch = std::find_if(
279 m_aCachedImplementations.begin(),
280 aEnd,
281 [&serviceName](CachePair const& cp)
282 { return serviceName == cp.first; }
284 if( aMatch != aEnd ) {
285 Reference<XInterface> xCanvas( use( aMatch->second, args, xContext ) );
286 if(xCanvas.is())
287 return xCanvas;
290 // lookup in available service list
291 const AvailVector::const_iterator aAvailEnd(m_aAvailableImplementations.end());
292 auto aAvailImplsMatch = std::find_if(
293 m_aAvailableImplementations.begin(),
294 aAvailEnd,
295 [&serviceName](AvailPair const& ap)
296 { return serviceName == ap.first; }
298 if( aAvailImplsMatch == aAvailEnd ) {
299 return Reference<XInterface>();
302 const AvailVector::const_iterator aAAEnd(m_aAAImplementations.end());
303 auto aAAImplsMatch = std::find_if(
304 m_aAAImplementations.begin(),
305 aAAEnd,
306 [&serviceName](AvailPair const& ap)
307 { return serviceName == ap.first; }
309 if( aAAImplsMatch == aAAEnd ) {
310 return Reference<XInterface>();
313 const AvailVector::const_iterator aAccelEnd(m_aAcceleratedImplementations.end());
314 auto aAccelImplsMatch = std::find_if(
315 m_aAcceleratedImplementations.begin(),
316 aAccelEnd,
317 [&serviceName](AvailPair const& ap)
318 { return serviceName == ap.first; }
320 if( aAccelImplsMatch == aAccelEnd ) {
321 return Reference<XInterface>();
324 const Sequence<OUString> aPreferredImpls( aAvailImplsMatch->second );
325 const OUString* pCurrImpl = aPreferredImpls.begin();
326 const OUString* const pEndImpl = aPreferredImpls.end();
328 const Sequence<OUString> aAAImpls( aAAImplsMatch->second );
330 const Sequence<OUString> aAccelImpls( aAccelImplsMatch->second );
332 // force last entry from impl list, if config flag set
333 if (bForceLastEntry && pCurrImpl != pEndImpl)
334 pCurrImpl = pEndImpl-1;
336 for(; pCurrImpl != pEndImpl; ++pCurrImpl)
338 const OUString aCurrName(pCurrImpl->trim());
340 // Skia works only with vclcanvas.
341 if( SkiaHelper::isVCLSkiaEnabled() && !aCurrName.endsWith(".VCL"))
342 continue;
344 // check whether given canvas service is listed in the
345 // sequence of "accelerated canvas implementations"
346 const bool bIsAcceleratedImpl(
347 std::any_of(aAccelImpls.begin(), aAccelImpls.end(),
348 [&aCurrName](OUString const& src)
349 { return aCurrName == o3tl::trim(src); }
352 // check whether given canvas service is listed in the
353 // sequence of "antialiasing canvas implementations"
354 const bool bIsAAImpl(
355 std::any_of(aAAImpls.begin(), aAAImpls.end(),
356 [&aCurrName](OUString const& src)
357 { return aCurrName == o3tl::trim(src); }
360 // try to instantiate canvas *only* if either accel and AA
361 // property match preference, *or*, if there's a mismatch, only
362 // go for a less capable canvas (that effectively let those
363 // pour canvas impls still work as fallbacks, should an
364 // accelerated/AA one fail). Property implies configuration:
365 // http://en.wikipedia.org/wiki/Truth_table#Logical_implication
366 if( (!bIsAAImpl || bUseAAEntry) && (!bIsAcceleratedImpl || bUseAcceleratedEntry) )
368 Reference<XInterface> xCanvas(use(aCurrName, args, xContext));
370 if(xCanvas.is())
372 if( aMatch != aEnd )
374 // cache entry exists, replace dysfunctional
375 // implementation name
376 aMatch->second = aCurrName;
378 else
380 // new service name, add new cache entry
381 m_aCachedImplementations.emplace_back(serviceName, aCurrName);
384 return xCanvas;
389 return Reference<XInterface>();
393 Reference<XInterface> CanvasFactory::createInstanceWithArgumentsAndContext(
394 OUString const & preferredOne, Sequence<Any> const & args,
395 Reference<XComponentContext> const & xContext )
397 Reference<XInterface> xCanvas(lookupAndUse(preferredOne, args, xContext));
398 if (!xCanvas.is())
399 // last resort: try service name directly
400 xCanvas = use(preferredOne, args, xContext);
402 if (xCanvas.is())
404 Reference<lang::XServiceName> xServiceName(xCanvas, uno::UNO_QUERY);
405 SAL_INFO("canvas", "using " << (xServiceName.is() ? xServiceName->getServiceName()
406 : u"(unknown)"_ustr));
408 return xCanvas;
411 // XMultiServiceFactory
413 Reference<XInterface> CanvasFactory::createInstance( OUString const & name )
415 return createInstanceWithArgumentsAndContext(
416 name, Sequence<Any>(), m_xContext );
420 Reference<XInterface> CanvasFactory::createInstanceWithArguments(
421 OUString const & name, Sequence<Any> const & args )
423 return createInstanceWithArgumentsAndContext(
424 name, args, m_xContext );
427 } // anon namespace
430 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
431 com_sun_star_comp_rendering_CanvasFactory_get_implementation(css::uno::XComponentContext* context,
432 css::uno::Sequence<css::uno::Any> const &)
434 return cppu::acquire(new CanvasFactory(context));
438 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */