00f8f75f36
Since I want to use them in the cppuhelper too, but comphelper is "above" cppuhelper in the dependency tree. And sharing the code between cppuhelper and the rest of LO across the URE boundary appears to be nigh impossible. Change-Id: I2ebf37746928dc820df43347dc1a2c158f00ec50 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151445 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
231 lines
7.9 KiB
C++
231 lines
7.9 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include <compbase2.hxx>
|
|
#include <sal/log.hxx>
|
|
#include <osl/diagnose.h>
|
|
|
|
namespace cppuhelper
|
|
{
|
|
WeakComponentImplHelperBase2::~WeakComponentImplHelperBase2() {}
|
|
|
|
// css::lang::XComponent
|
|
void SAL_CALL WeakComponentImplHelperBase2::dispose()
|
|
{
|
|
std::unique_lock aGuard(m_aMutex);
|
|
if (m_bDisposed)
|
|
return;
|
|
m_bDisposed = true;
|
|
disposing(aGuard);
|
|
if (!aGuard.owns_lock())
|
|
aGuard.lock();
|
|
css::lang::EventObject aEvt(static_cast<OWeakObject*>(this));
|
|
maEventListeners.disposeAndClear(aGuard, aEvt);
|
|
}
|
|
|
|
void WeakComponentImplHelperBase2::disposing(std::unique_lock<std::mutex>&) {}
|
|
|
|
void SAL_CALL WeakComponentImplHelperBase2::addEventListener(
|
|
css::uno::Reference<css::lang::XEventListener> const& rxListener)
|
|
{
|
|
std::unique_lock aGuard(m_aMutex);
|
|
if (m_bDisposed)
|
|
return;
|
|
maEventListeners.addInterface(aGuard, rxListener);
|
|
}
|
|
|
|
void SAL_CALL WeakComponentImplHelperBase2::removeEventListener(
|
|
css::uno::Reference<css::lang::XEventListener> const& rxListener)
|
|
{
|
|
std::unique_lock aGuard(m_aMutex);
|
|
maEventListeners.removeInterface(aGuard, rxListener);
|
|
}
|
|
|
|
css::uno::Any SAL_CALL WeakComponentImplHelperBase2::queryInterface(css::uno::Type const& rType)
|
|
{
|
|
css::uno::Any aReturn = ::cppu::queryInterface(rType, static_cast<css::uno::XWeak*>(this),
|
|
static_cast<css::lang::XComponent*>(this));
|
|
if (aReturn.hasValue())
|
|
return aReturn;
|
|
return OWeakObject::queryInterface(rType);
|
|
}
|
|
|
|
static void checkInterface(css::uno::Type const& rType)
|
|
{
|
|
if (css::uno::TypeClass_INTERFACE != rType.getTypeClass())
|
|
{
|
|
OUString msg("querying for interface \"" + rType.getTypeName() + "\": no interface type!");
|
|
SAL_WARN("cppuhelper", msg);
|
|
throw css::uno::RuntimeException(msg);
|
|
}
|
|
}
|
|
|
|
static bool isXInterface(rtl_uString* pStr)
|
|
{
|
|
return OUString::unacquired(&pStr) == "com.sun.star.uno.XInterface";
|
|
}
|
|
|
|
static bool td_equals(typelib_TypeDescriptionReference const* pTDR1,
|
|
typelib_TypeDescriptionReference const* pTDR2)
|
|
{
|
|
return ((pTDR1 == pTDR2)
|
|
|| OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName));
|
|
}
|
|
|
|
static cppu::type_entry* getTypeEntries(cppu::class_data* cd)
|
|
{
|
|
cppu::type_entry* pEntries = cd->m_typeEntries;
|
|
if (!cd->m_storedTypeRefs) // not inited?
|
|
{
|
|
static std::mutex aMutex;
|
|
std::scoped_lock guard(aMutex);
|
|
if (!cd->m_storedTypeRefs) // not inited?
|
|
{
|
|
// get all types
|
|
for (sal_Int32 n = cd->m_nTypes; n--;)
|
|
{
|
|
cppu::type_entry* pEntry = &pEntries[n];
|
|
css::uno::Type const& rType = (*pEntry->m_type.getCppuType)(nullptr);
|
|
OSL_ENSURE(rType.getTypeClass() == css::uno::TypeClass_INTERFACE,
|
|
"### wrong helper init: expected interface!");
|
|
OSL_ENSURE(
|
|
!isXInterface(rType.getTypeLibType()->pTypeName),
|
|
"### want to implement XInterface: template argument is XInterface?!?!?!");
|
|
if (rType.getTypeClass() != css::uno::TypeClass_INTERFACE)
|
|
{
|
|
OUString msg("type \"" + rType.getTypeName() + "\" is no interface type!");
|
|
SAL_WARN("cppuhelper", msg);
|
|
throw css::uno::RuntimeException(msg);
|
|
}
|
|
// ref is statically held by getCppuType()
|
|
pEntry->m_type.typeRef = rType.getTypeLibType();
|
|
}
|
|
OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
|
|
cd->m_storedTypeRefs = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
|
|
}
|
|
return pEntries;
|
|
}
|
|
|
|
static void* makeInterface(sal_IntPtr nOffset, void* that)
|
|
{
|
|
return (static_cast<char*>(that) + nOffset);
|
|
}
|
|
|
|
static bool recursivelyFindType(typelib_TypeDescriptionReference const* demandedType,
|
|
typelib_InterfaceTypeDescription const* type, sal_IntPtr* offset)
|
|
{
|
|
// This code assumes that the vtables of a multiple-inheritance class (the
|
|
// offset amount by which to adjust the this pointer) follow one another in
|
|
// the object layout, and that they contain slots for the inherited classes
|
|
// in a specific order. In theory, that need not hold for any given
|
|
// platform; in practice, it seems to work well on all supported platforms:
|
|
next:
|
|
for (sal_Int32 i = 0; i < type->nBaseTypes; ++i)
|
|
{
|
|
if (i > 0)
|
|
{
|
|
*offset += sizeof(void*);
|
|
}
|
|
typelib_InterfaceTypeDescription const* base = type->ppBaseTypes[i];
|
|
// ignore XInterface:
|
|
if (base->nBaseTypes > 0)
|
|
{
|
|
if (td_equals(reinterpret_cast<typelib_TypeDescriptionReference const*>(base),
|
|
demandedType))
|
|
{
|
|
return true;
|
|
}
|
|
// Profiling showed that it is important to speed up the common case
|
|
// of only one base:
|
|
if (type->nBaseTypes == 1)
|
|
{
|
|
type = base;
|
|
goto next;
|
|
}
|
|
if (recursivelyFindType(demandedType, base, offset))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void* queryDeepNoXInterface(typelib_TypeDescriptionReference const* pDemandedTDR,
|
|
cppu::class_data* cd, void* that)
|
|
{
|
|
cppu::type_entry* pEntries = getTypeEntries(cd);
|
|
sal_Int32 nTypes = cd->m_nTypes;
|
|
sal_Int32 n;
|
|
|
|
// try top interfaces without getting td
|
|
for (n = 0; n < nTypes; ++n)
|
|
{
|
|
if (td_equals(pEntries[n].m_type.typeRef, pDemandedTDR))
|
|
{
|
|
return makeInterface(pEntries[n].m_offset, that);
|
|
}
|
|
}
|
|
// query deep getting td
|
|
for (n = 0; n < nTypes; ++n)
|
|
{
|
|
typelib_TypeDescription* pTD = nullptr;
|
|
TYPELIB_DANGER_GET(&pTD, pEntries[n].m_type.typeRef);
|
|
if (pTD)
|
|
{
|
|
// exclude top (already tested) and bottom (XInterface) interface
|
|
OSL_ENSURE(reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD)->nBaseTypes > 0,
|
|
"### want to implement XInterface:"
|
|
" template argument is XInterface?!?!?!");
|
|
sal_IntPtr offset = pEntries[n].m_offset;
|
|
bool found = recursivelyFindType(
|
|
pDemandedTDR, reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD), &offset);
|
|
TYPELIB_DANGER_RELEASE(pTD);
|
|
if (found)
|
|
{
|
|
return makeInterface(offset, that);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OUString msg("cannot get type description for type \""
|
|
+ OUString::unacquired(&pEntries[n].m_type.typeRef->pTypeName) + "\"!");
|
|
SAL_WARN("cppuhelper", msg);
|
|
throw css::uno::RuntimeException(msg);
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
css::uno::Any WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
|
|
WeakComponentImplHelperBase2* pBase)
|
|
{
|
|
checkInterface(rType);
|
|
typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
|
|
|
|
// shortcut XInterface to WeakComponentImplHelperBase
|
|
if (!isXInterface(pTDR->pTypeName))
|
|
{
|
|
void* p = queryDeepNoXInterface(pTDR, cd, pBase);
|
|
if (p)
|
|
{
|
|
return css::uno::Any(&p, pTDR);
|
|
}
|
|
}
|
|
return pBase->cppuhelper::WeakComponentImplHelperBase2::queryInterface(rType);
|
|
}
|
|
|
|
} // namespace cppuextra
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|