LibreOffice Module canvas (master)  1
cf_service.cxx
Go to the documentation of this file.
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 #include <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include <algorithm>
24 #include <utility>
25 #include <vector>
26 
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>
35 #include <cppuhelper/implbase.hxx>
37 #include <osl/mutex.hxx>
38 #include <o3tl/functional.hxx>
39 #include <config_features.h>
40 #if HAVE_FEATURE_OPENGL
42 #endif
43 #include <vcl/skia/SkiaHelper.hxx>
44 #include <unotools/configmgr.hxx>
45 
46 using namespace ::com::sun::star;
47 using namespace ::com::sun::star::uno;
48 
49 
50 namespace
51 {
52 
53 class CanvasFactory
54  : public ::cppu::WeakImplHelper< lang::XServiceInfo,
55  lang::XMultiComponentFactory,
56  lang::XMultiServiceFactory >
57 {
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;
62 
63 
64  mutable ::osl::Mutex m_mutex;
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;
74 
75  void checkConfigFlag( bool& r_bFlag,
76  bool& r_CacheFlag,
77  const OUString& nodeName ) const;
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;
85 
86 public:
87  virtual ~CanvasFactory() override;
88  explicit CanvasFactory( Reference<XComponentContext> const & xContext );
89 
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;
94 
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;
105 
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;
111 };
112 
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()
124 {
126  {
127  try
128  {
129  // read out configuration for preferred services:
130  Reference<lang::XMultiServiceFactory> xConfigProvider(
131  configuration::theDefaultProvider::get( m_xContext ) );
132 
133  uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
134  {
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 );
142 
143  uno::Sequence<uno::Any> aArgs2(comphelper::InitAnyPropertySequence(
144  {
145  {"nodepath", uno::Any(OUString("/org.openoffice.Office.Canvas/CanvasServiceList"))}
146  }));
148  xConfigProvider->createInstanceWithArguments(
149  "com.sun.star.configuration.ConfigurationAccess",
150  aArgs2 ), UNO_QUERY_THROW );
151  Reference<container::XHierarchicalNameAccess> xHierarchicalNameAccess(
152  xNameAccess, UNO_QUERY_THROW);
153 
154  Sequence<OUString> serviceNames = xNameAccess->getElementNames();
155  const OUString* pCurr = serviceNames.getConstArray();
156  const OUString* const pEnd = pCurr + serviceNames.getLength();
157  while( pCurr != pEnd )
158  {
159  Reference<container::XNameAccess> xEntryNameAccess(
160  xHierarchicalNameAccess->getByHierarchicalName(*pCurr),
161  UNO_QUERY );
162 
163  if( xEntryNameAccess.is() )
164  {
165  Sequence<OUString> implementationList;
166  if( xEntryNameAccess->getByName("PreferredImplementations") >>= implementationList )
167  {
168  m_aAvailableImplementations.emplace_back(*pCurr,implementationList );
169  }
170  if( xEntryNameAccess->getByName("AcceleratedImplementations") >>= implementationList )
171  {
172  m_aAcceleratedImplementations.emplace_back(*pCurr,implementationList );
173  }
174  if( xEntryNameAccess->getByName("AntialiasingImplementations") >>= implementationList )
175  {
176  m_aAAImplementations.emplace_back(*pCurr,implementationList );
177  }
178 
179  }
180 
181  ++pCurr;
182  }
183  }
184  catch (const RuntimeException &)
185  {
186  throw;
187  }
188  catch (const Exception&)
189  {
190  }
191  }
192 
193  if (m_aAvailableImplementations.empty())
194  {
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 );
200 
201  aServices[0] = "com.sun.star.comp.rendering.SpriteCanvas.VCL";
202  m_aAvailableImplementations.emplace_back(OUString("com.sun.star.rendering.SpriteCanvas"),
203  aServices );
204  }
205 }
206 
207 CanvasFactory::~CanvasFactory()
208 {
209 }
210 
211 
212 // XServiceInfo
213 OUString CanvasFactory::getImplementationName()
214 {
215  return "com.sun.star.comp.rendering.CanvasFactory";
216 }
217 
218 sal_Bool CanvasFactory::supportsService( OUString const & serviceName )
219 {
220  return cppu::supportsService(this, serviceName);
221 }
222 
223 Sequence<OUString> CanvasFactory::getSupportedServiceNames()
224 {
225  return { "com.sun.star.rendering.CanvasFactory" };
226 }
227 
228 // XMultiComponentFactory
229 Sequence<OUString> CanvasFactory::getAvailableServiceNames()
230 {
231  Sequence<OUString> aServiceNames(m_aAvailableImplementations.size());
232  std::transform(m_aAvailableImplementations.begin(),
233  m_aAvailableImplementations.end(),
234  aServiceNames.getArray(),
236  return aServiceNames;
237 }
238 
239 Reference<XInterface> CanvasFactory::createInstanceWithContext(
240  OUString const & name, Reference<XComponentContext> const & xContext )
241 {
242  return createInstanceWithArgumentsAndContext(
243  name, Sequence<Any>(), xContext );
244 }
245 
246 
247 Reference<XInterface> CanvasFactory::use(
248  OUString const & serviceName,
249  Sequence<Any> const & args,
250  Reference<XComponentContext> const & xContext ) const
251 {
252  try {
253  return m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
254  serviceName, args, xContext);
255  }
256  catch (css::lang::IllegalArgumentException &)
257  {
258  return Reference<XInterface>();
259  }
260  catch (const RuntimeException &)
261  {
262  throw;
263  }
264  catch (const Exception &)
265  {
266  return Reference<XInterface>();
267  }
268 }
269 
270 
271 void CanvasFactory::checkConfigFlag( bool& r_bFlag,
272  bool& r_CacheFlag,
273  const OUString& nodeName ) const
274 {
275  if( m_xCanvasConfigNameAccess.is() )
276  {
277  m_xCanvasConfigNameAccess->getByName( nodeName ) >>= r_bFlag;
278 
279  if( r_CacheFlag != r_bFlag )
280  {
281  // cache is invalid, because of different order of
282  // elements
283  r_CacheFlag = r_bFlag;
284  m_aCachedImplementations.clear();
285  }
286  }
287 }
288 
289 
290 Reference<XInterface> CanvasFactory::lookupAndUse(
291  OUString const & serviceName, Sequence<Any> const & args,
292  Reference<XComponentContext> const & xContext ) const
293 {
294  ::osl::MutexGuard guard(m_mutex);
295 
296  // forcing last entry from impl list, if config flag set
297  bool bForceLastEntry(false);
298  checkConfigFlag( bForceLastEntry,
299  m_bCacheHasForcedLastImpl,
300  "ForceSafeServiceImpl" );
301 
302  // tdf#93870 - force VCL canvas in OpenGL mode for now.
303 #if HAVE_FEATURE_OPENGL
305  bForceLastEntry = true;
306 #endif
308  bForceLastEntry = true;
309 
310  // use anti-aliasing canvas, if config flag set (or not existing)
311  bool bUseAAEntry(true);
312  checkConfigFlag( bUseAAEntry,
313  m_bCacheHasUseAAEntry,
314  "UseAntialiasingCanvas" );
315 
316  // use accelerated canvas, if config flag set (or not existing)
317  bool bUseAcceleratedEntry(true);
318  checkConfigFlag( bUseAcceleratedEntry,
319  m_bCacheHasUseAcceleratedEntry,
320  "UseAcceleratedCanvas" );
321 
322  // try to reuse last working implementation for given service name
323  const CacheVector::iterator aEnd(m_aCachedImplementations.end());
324  auto aMatch = std::find_if(
325  m_aCachedImplementations.begin(),
326  aEnd,
327  [&serviceName](CachePair const& cp)
328  { return serviceName == cp.first; }
329  );
330  if( aMatch != aEnd ) {
331  Reference<XInterface> xCanvas( use( aMatch->second, args, xContext ) );
332  if(xCanvas.is())
333  return xCanvas;
334  }
335 
336  // lookup in available service list
337  const AvailVector::const_iterator aAvailEnd(m_aAvailableImplementations.end());
338  auto aAvailImplsMatch = std::find_if(
339  m_aAvailableImplementations.begin(),
340  aAvailEnd,
341  [&serviceName](AvailPair const& ap)
342  { return serviceName == ap.first; }
343  );
344  if( aAvailImplsMatch == aAvailEnd ) {
345  return Reference<XInterface>();
346  }
347 
348  const AvailVector::const_iterator aAAEnd(m_aAAImplementations.end());
349  auto aAAImplsMatch = std::find_if(
350  m_aAAImplementations.begin(),
351  aAAEnd,
352  [&serviceName](AvailPair const& ap)
353  { return serviceName == ap.first; }
354  );
355  if( aAAImplsMatch == aAAEnd ) {
356  return Reference<XInterface>();
357  }
358 
359  const AvailVector::const_iterator aAccelEnd(m_aAcceleratedImplementations.end());
360  auto aAccelImplsMatch = std::find_if(
361  m_aAcceleratedImplementations.begin(),
362  aAccelEnd,
363  [&serviceName](AvailPair const& ap)
364  { return serviceName == ap.first; }
365  );
366  if( aAccelImplsMatch == aAccelEnd ) {
367  return Reference<XInterface>();
368  }
369 
370  const Sequence<OUString> aPreferredImpls( aAvailImplsMatch->second );
371  const OUString* pCurrImpl = aPreferredImpls.getConstArray();
372  const OUString* const pEndImpl = pCurrImpl + aPreferredImpls.getLength();
373 
374  const Sequence<OUString> aAAImpls( aAAImplsMatch->second );
375  const OUString* const pFirstAAImpl = aAAImpls.getConstArray();
376  const OUString* const pEndAAImpl = pFirstAAImpl + aAAImpls.getLength();
377 
378  const Sequence<OUString> aAccelImpls( aAccelImplsMatch->second );
379  const OUString* const pFirstAccelImpl = aAccelImpls.getConstArray();
380  const OUString* const pEndAccelImpl = pFirstAccelImpl + aAccelImpls.getLength();
381 
382  // force last entry from impl list, if config flag set
383  if( bForceLastEntry )
384  pCurrImpl = pEndImpl-1;
385 
386  while( pCurrImpl != pEndImpl )
387  {
388  const OUString aCurrName(pCurrImpl->trim());
389 
390  // check whether given canvas service is listed in the
391  // sequence of "accelerated canvas implementations"
392  const bool bIsAcceleratedImpl(
393  std::any_of(pFirstAccelImpl,
394  pEndAccelImpl,
395  [&aCurrName](OUString const& src)
396  { return aCurrName == src.trim(); }
397  ));
398 
399  // check whether given canvas service is listed in the
400  // sequence of "antialiasing canvas implementations"
401  const bool bIsAAImpl(
402  std::any_of(pFirstAAImpl,
403  pEndAAImpl,
404  [&aCurrName](OUString const& src)
405  { return aCurrName == src.trim(); }
406  ));
407 
408  // try to instantiate canvas *only* if either accel and AA
409  // property match preference, *or*, if there's a mismatch, only
410  // go for a less capable canvas (that effectively let those
411  // pour canvas impls still work as fallbacks, should an
412  // accelerated/AA one fail). Property implies configuration:
413  // http://en.wikipedia.org/wiki/Truth_table#Logical_implication
414  if( (!bIsAAImpl || bUseAAEntry) && (!bIsAcceleratedImpl || bUseAcceleratedEntry) )
415  {
416  Reference<XInterface> xCanvas(
417  use( pCurrImpl->trim(), args, xContext ) );
418 
419  if(xCanvas.is())
420  {
421  if( aMatch != aEnd )
422  {
423  // cache entry exists, replace dysfunctional
424  // implementation name
425  aMatch->second = pCurrImpl->trim();
426  }
427  else
428  {
429  // new service name, add new cache entry
430  m_aCachedImplementations.emplace_back(serviceName,
431  pCurrImpl->trim());
432  }
433 
434  return xCanvas;
435  }
436  }
437 
438  ++pCurrImpl;
439  }
440 
441  return Reference<XInterface>();
442 }
443 
444 
445 Reference<XInterface> CanvasFactory::createInstanceWithArgumentsAndContext(
446  OUString const & preferredOne, Sequence<Any> const & args,
447  Reference<XComponentContext> const & xContext )
448 {
449  Reference<XInterface> xCanvas(lookupAndUse(preferredOne, args, xContext));
450  if (!xCanvas.is())
451  // last resort: try service name directly
452  xCanvas = use(preferredOne, args, xContext);
453 
454  if (xCanvas.is())
455  {
456  Reference<lang::XServiceName> xServiceName(xCanvas, uno::UNO_QUERY);
457  SAL_INFO("canvas", "using " << (xServiceName.is() ? xServiceName->getServiceName()
458  : OUString("(unknown)")));
459  }
460  return xCanvas;
461 }
462 
463 // XMultiServiceFactory
464 
465 Reference<XInterface> CanvasFactory::createInstance( OUString const & name )
466 {
467  return createInstanceWithArgumentsAndContext(
468  name, Sequence<Any>(), m_xContext );
469 }
470 
471 
472 Reference<XInterface> CanvasFactory::createInstanceWithArguments(
473  OUString const & name, Sequence<Any> const & args )
474 {
475  return createInstanceWithArgumentsAndContext(
476  name, args, m_xContext );
477 }
478 
479 } // anon namespace
480 
481 
482 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
484  css::uno::Sequence<css::uno::Any> const &)
485 {
486  return cppu::acquire(new CanvasFactory(context));
487 }
488 
489 
490 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OUString getImplementationName()
Sequence< OUString > aServiceNames
static bool IsFuzzing()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
static bool isVCLOpenGLEnabled()
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_rendering_CanvasFactory_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
Definition: cf_service.cxx:483
css::uno::Sequence< OUString > getSupportedServiceNames()
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
HRESULT createInstance(REFIID iid, Ifc **ppIfc)
unsigned char sal_Bool
Mutex m_mutex
VCL_DLLPUBLIC bool isVCLSkiaEnabled()
#define SAL_INFO(area, stream)
Reference< XComponentContext > m_xContext