loplugin:unocast (cairocanvas::SurfaceProvider)

(See the upcoming commit introducing that loplugin:unocast on why such
dynamic_casts from UNO types are dangerous.)

There are implementation classes whose getSomething already delegates to
RepaintTarget, so they can't also delegate to SurfaceProvider.  So introduce the
concept of comphelper::getSomethingImpl additionally delegating to a sequence of
mixin classes before delegating to the base.

Change-Id: I9230f3dc06abbdd1ad92514a11473dae2624f7c1
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144404
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
This commit is contained in:
Stephan Bergmann
2022-12-15 11:44:32 +01:00
parent 9a0b523e0a
commit 4844c096a8
7 changed files with 92 additions and 8 deletions

View File

@@ -24,6 +24,7 @@
#include <com/sun/star/lang/NoSupportException.hpp>
#include <osl/mutex.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <comphelper/servicehelper.hxx>
#include <vcl/sysdata.hxx>
#include <vcl/skia/SkiaHelper.hxx>
#include <cppuhelper/supportsservice.hxx>
@@ -129,7 +130,9 @@ namespace cairocanvas
}
sal_Int64 Canvas::getSomething(css::uno::Sequence<sal_Int8> const & aIdentifier) {
return RepaintTarget::getSomething(aIdentifier);
return comphelper::getSomethingImpl_skipDerived(
aIdentifier, this, comphelper::MixinToGetSomethingOf<SurfaceProvider>{},
comphelper::FallbackToGetSomethingOf<RepaintTarget>{});
}
bool Canvas::repaint( const SurfaceSharedPtr& pSurface,

View File

@@ -145,7 +145,8 @@ namespace cairocanvas
sal_Int64 CanvasBitmap::getSomething(css::uno::Sequence<sal_Int8> const & aIdentifier) {
return comphelper::getSomethingImpl(
aIdentifier, this, comphelper::FallbackToGetSomethingOf<RepaintTarget>{});
aIdentifier, this, comphelper::MixinToGetSomethingOf<SurfaceProvider>{},
comphelper::FallbackToGetSomethingOf<RepaintTarget>{});
}
css::uno::Sequence<sal_Int8> const & CanvasBitmap::getUnoTunnelId() {

View File

@@ -148,7 +148,9 @@ namespace cairocanvas
}
sal_Int64 CanvasCustomSprite::getSomething(css::uno::Sequence<sal_Int8> const & aIdentifier) {
return RepaintTarget::getSomething(aIdentifier);
return comphelper::getSomethingImpl_skipDerived(
aIdentifier, this, comphelper::MixinToGetSomethingOf<SurfaceProvider>{},
comphelper::FallbackToGetSomethingOf<RepaintTarget>{});
}
}

View File

@@ -299,7 +299,8 @@ constexpr OUStringLiteral PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME = u"Canvas::
if( pBitmapImpl )
return pBitmapImpl->getSurface();
SurfaceProvider* pSurfaceProvider = dynamic_cast<SurfaceProvider*>( xBitmap.get() );
SurfaceProvider* pSurfaceProvider
= comphelper::getFromUnoTunnel<SurfaceProvider>( xBitmap );
if( pSurfaceProvider )
return pSurfaceProvider->getSurface();

View File

@@ -152,7 +152,9 @@ namespace cairocanvas
}
sal_Int64 SpriteCanvas::getSomething(css::uno::Sequence<sal_Int8> const & aIdentifier) {
return RepaintTarget::getSomething(aIdentifier);
return comphelper::getSomethingImpl_skipDerived(
aIdentifier, this, comphelper::MixinToGetSomethingOf<SurfaceProvider>{},
comphelper::FallbackToGetSomethingOf<RepaintTarget>{});
}
SurfaceSharedPtr SpriteCanvas::getSurface()

View File

@@ -20,7 +20,10 @@
#pragma once
#include <rtl/ref.hxx>
#include <com/sun/star/uno/Sequence.hxx>
#include <com/sun/star/uno/XInterface.hpp>
#include <comphelper/servicehelper.hxx>
#include <sal/types.h>
#include <basegfx/vector/b2isize.hxx>
#include <vcl/cairo.hxx>
@@ -37,7 +40,7 @@ namespace cairocanvas
This interface must be implemented on all canvas
implementations that hand out XCachedPrimitives
*/
class SAL_LOPLUGIN_ANNOTATE("crosscast") SurfaceProvider : public css::uno::XInterface
class SurfaceProvider : public css::uno::XInterface
{
public:
virtual ~SurfaceProvider() {}
@@ -62,6 +65,15 @@ namespace cairocanvas
/** Provides the underlying vcl outputdevice this surface renders on
*/
virtual OutputDevice* getOutputDevice() = 0;
sal_Int64 getSomething(css::uno::Sequence<sal_Int8> const & aIdentifier) {
return comphelper::getSomethingImpl(aIdentifier, this);
}
static css::uno::Sequence<sal_Int8> const & getUnoTunnelId() {
static comphelper::UnoIdInit const id;
return id.getSeq();
}
};
typedef ::rtl::Reference< SurfaceProvider > SurfaceProviderRef;

View File

@@ -82,6 +82,16 @@ namespace comphelper {
&& memcmp(T::getUnoTunnelId().getConstArray(), rId.getConstArray(), 16) == 0;
}
template<typename T> struct MixinToGetSomethingOf {
static bool get(css::uno::Sequence<sal_Int8> const & id, T * p, sal_Int64 * result) {
if (!isUnoTunnelId<T>(id)) {
return false;
}
*result = getSomething_cast(p);
return true;
}
};
template <class Base> struct FallbackToGetSomethingOf
{
static sal_Int64 get(const css::uno::Sequence<sal_Int8>& rId, Base* p)
@@ -95,12 +105,65 @@ namespace comphelper {
static sal_Int64 get(const css::uno::Sequence<sal_Int8>&, void*) { return 0; }
};
// There are five cases how to implement T::getSomething:
// (1) Delegate to Base:
// Either, if Base has only getUnoTunnelId but no getSomething:
// return getSomethingImpl<Base>(aIdentifier, this);
// Or, if Base has getSomething:
// return Base::getSomething(aIdentifier)
// (2) Check against T::getUnoTunnelId, else return 0:
// return getSomethingImpl(aIdentifier, this);
// (3) Check against T::getUnoTunnelId, else delegate to Base:
// return getSomethingImpl(aIdentifier, this, FallbackToGetSomethingOf<Base>{});
// (4) Check against T::getUnoTunnelId, else check against each Mixins::getUnoTunnelId, else
// delegate to Base:
// return getSomethingImpl(
// aIdentifier, this, MixinToGetSomethingOf<Mixin1>{}, ...,
// MixinToGetSomethingOf<MixinN>{}, FallbackToGetSomethingOf<Base>{});
// (5) Check against each Mixins::getUnoTunnelId, else delegate to Base:
// return getSomethingImpl_skipDerived(
// aIdentifier, this, MixinToGetSomethingOf<Mixin1>{}, ...,
// MixinToGetSomethingOf<MixinN>{}, FallbackToGetSomethingOf<Base>{});
template <class T, class Base = void>
sal_Int64 getSomethingImpl(const css::uno::Sequence<sal_Int8>& rId, T* pThis,
FallbackToGetSomethingOf<Base> = {})
{
if (isUnoTunnelId<T>(rId))
return getSomething_cast(pThis);
sal_Int64 res;
if (MixinToGetSomethingOf<T>::get(rId, pThis, &res)) {
return res;
}
return FallbackToGetSomethingOf<Base>::get(rId, pThis);
}
template <class T, class Mixin, class... Mixins, class Base>
sal_Int64 getSomethingImpl(const css::uno::Sequence<sal_Int8>& rId, T* pThis,
MixinToGetSomethingOf<Mixin>, MixinToGetSomethingOf<Mixins>...,
FallbackToGetSomethingOf<Base>)
{
sal_Int64 res;
if (((MixinToGetSomethingOf<T>::get(rId, pThis, &res)
|| MixinToGetSomethingOf<Mixin>::get(rId, pThis, &res)) || ...
|| MixinToGetSomethingOf<Mixins>::get(rId, pThis, &res)))
{
return res;
}
return FallbackToGetSomethingOf<Base>::get(rId, pThis);
}
template <class T, class Mixin, class... Mixins, class Base>
sal_Int64 getSomethingImpl_skipDerived(const css::uno::Sequence<sal_Int8>& rId, T* pThis,
MixinToGetSomethingOf<Mixin>, MixinToGetSomethingOf<Mixins>...,
FallbackToGetSomethingOf<Base>)
{
sal_Int64 res;
if ((MixinToGetSomethingOf<Mixin>::get(rId, pThis, &res) || ...
|| MixinToGetSomethingOf<Mixins>::get(rId, pThis, &res)))
{
return res;
}
return FallbackToGetSomethingOf<Base>::get(rId, pThis);
}