canvas/source/cairo/cairo_canvas.cxx             |    5 +
 canvas/source/cairo/cairo_canvasbitmap.cxx       |    3 -
 canvas/source/cairo/cairo_canvascustomsprite.cxx |    4 +
 canvas/source/cairo/cairo_canvashelper.cxx       |    3 -
 canvas/source/cairo/cairo_spritecanvas.cxx       |    4 +
 canvas/source/cairo/cairo_surfaceprovider.hxx    |   14 ++++
 include/comphelper/servicehelper.hxx             |   67 ++++++++++++++++++++++-
 7 files changed, 92 insertions(+), 8 deletions(-)

New commits:
commit 4844c096a8ab6a9a620c410a0949d4499f12a504
Author:     Stephan Bergmann <sberg...@redhat.com>
AuthorDate: Thu Dec 15 11:44:32 2022 +0100
Commit:     Stephan Bergmann <sberg...@redhat.com>
CommitDate: Sun Dec 18 18:31:37 2022 +0000

    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 <sberg...@redhat.com>

diff --git a/canvas/source/cairo/cairo_canvas.cxx 
b/canvas/source/cairo/cairo_canvas.cxx
index 6c9e4fe296df..255b8d84d80c 100644
--- a/canvas/source/cairo/cairo_canvas.cxx
+++ b/canvas/source/cairo/cairo_canvas.cxx
@@ -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,
diff --git a/canvas/source/cairo/cairo_canvasbitmap.cxx 
b/canvas/source/cairo/cairo_canvasbitmap.cxx
index 3e0bcae618f6..30ccb2cda8e8 100644
--- a/canvas/source/cairo/cairo_canvasbitmap.cxx
+++ b/canvas/source/cairo/cairo_canvasbitmap.cxx
@@ -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() {
diff --git a/canvas/source/cairo/cairo_canvascustomsprite.cxx 
b/canvas/source/cairo/cairo_canvascustomsprite.cxx
index 98ead7036b34..e5f22e9c4a9c 100644
--- a/canvas/source/cairo/cairo_canvascustomsprite.cxx
+++ b/canvas/source/cairo/cairo_canvascustomsprite.cxx
@@ -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>{});
     }
 }
 
diff --git a/canvas/source/cairo/cairo_canvashelper.cxx 
b/canvas/source/cairo/cairo_canvashelper.cxx
index 9279a4c0781b..89a794bc6cd5 100644
--- a/canvas/source/cairo/cairo_canvashelper.cxx
+++ b/canvas/source/cairo/cairo_canvashelper.cxx
@@ -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();
 
diff --git a/canvas/source/cairo/cairo_spritecanvas.cxx 
b/canvas/source/cairo/cairo_spritecanvas.cxx
index e414f8d8d9b5..2d33d4a14c7a 100644
--- a/canvas/source/cairo/cairo_spritecanvas.cxx
+++ b/canvas/source/cairo/cairo_spritecanvas.cxx
@@ -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()
diff --git a/canvas/source/cairo/cairo_surfaceprovider.hxx 
b/canvas/source/cairo/cairo_surfaceprovider.hxx
index 1ff6f2aa7d3f..e0293373451f 100644
--- a/canvas/source/cairo/cairo_surfaceprovider.hxx
+++ b/canvas/source/cairo/cairo_surfaceprovider.hxx
@@ -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;
diff --git a/include/comphelper/servicehelper.hxx 
b/include/comphelper/servicehelper.hxx
index c225494ccf1b..1d157cbf1482 100644
--- a/include/comphelper/servicehelper.hxx
+++ b/include/comphelper/servicehelper.hxx
@@ -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);
     }

Reply via email to