/src/libreoffice/comphelper/source/misc/compbase.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ |
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 | | |
10 | | #include <comphelper/compbase.hxx> |
11 | | #include <cppuhelper/queryinterface.hxx> |
12 | | #include <sal/log.hxx> |
13 | | #include <osl/diagnose.h> |
14 | | |
15 | | namespace comphelper |
16 | | { |
17 | 561k | WeakComponentImplHelperBase::~WeakComponentImplHelperBase() {} |
18 | | |
19 | | // css::lang::XComponent |
20 | | void SAL_CALL WeakComponentImplHelperBase::dispose() |
21 | 102k | { |
22 | 102k | std::unique_lock aGuard(m_aMutex); |
23 | 102k | if (m_bDisposed) |
24 | 0 | return; |
25 | 102k | m_bDisposed = true; |
26 | 102k | disposing(aGuard); |
27 | 102k | if (!aGuard.owns_lock()) |
28 | 0 | aGuard.lock(); |
29 | 102k | css::lang::EventObject aEvt(static_cast<OWeakObject*>(this)); |
30 | 102k | maEventListeners.disposeAndClear(aGuard, aEvt); |
31 | 102k | } |
32 | | |
33 | | // This is only called from the destructor to do cleanup that |
34 | | // might not have occurred |
35 | | void WeakComponentImplHelperBase::disposeOnDestruct() |
36 | 0 | { |
37 | 0 | std::unique_lock aGuard(m_aMutex); |
38 | 0 | assert(m_refCount == 0 && "only supposed to be called from the destructor"); |
39 | 0 | if (m_bDisposed) |
40 | 0 | return; |
41 | 0 | m_bDisposed = true; |
42 | | // bump the ref-count so we don't accidentally do a double delete |
43 | | // if something else increases and then decreases our ref-count |
44 | 0 | cppu::OWeakObject::acquire(); |
45 | 0 | disposing(aGuard); |
46 | 0 | } |
47 | | |
48 | 22.5k | void WeakComponentImplHelperBase::disposing(std::unique_lock<std::mutex>&) {} |
49 | | |
50 | | void SAL_CALL WeakComponentImplHelperBase::addEventListener( |
51 | | css::uno::Reference<css::lang::XEventListener> const& rxListener) |
52 | 98.0k | { |
53 | 98.0k | std::unique_lock aGuard(m_aMutex); |
54 | 98.0k | if (m_bDisposed) |
55 | 0 | return; |
56 | 98.0k | maEventListeners.addInterface(aGuard, rxListener); |
57 | 98.0k | } |
58 | | |
59 | | void SAL_CALL WeakComponentImplHelperBase::removeEventListener( |
60 | | css::uno::Reference<css::lang::XEventListener> const& rxListener) |
61 | 84.6k | { |
62 | 84.6k | std::unique_lock aGuard(m_aMutex); |
63 | 84.6k | maEventListeners.removeInterface(aGuard, rxListener); |
64 | 84.6k | } |
65 | | |
66 | | css::uno::Any SAL_CALL WeakComponentImplHelperBase::queryInterface(css::uno::Type const& rType) |
67 | 112k | { |
68 | 112k | css::uno::Any aReturn = ::cppu::queryInterface(rType, static_cast<css::uno::XWeak*>(this), |
69 | 112k | static_cast<css::lang::XComponent*>(this)); |
70 | 112k | if (aReturn.hasValue()) |
71 | 82.3k | return aReturn; |
72 | 30.1k | return OWeakObject::queryInterface(rType); |
73 | 112k | } |
74 | | |
75 | | static void checkInterface(css::uno::Type const& rType) |
76 | 2.38M | { |
77 | 2.38M | if (css::uno::TypeClass_INTERFACE != rType.getTypeClass()) |
78 | 0 | { |
79 | 0 | OUString msg("querying for interface \"" + rType.getTypeName() + "\": no interface type!"); |
80 | 0 | SAL_WARN("cppuhelper", msg); |
81 | 0 | throw css::uno::RuntimeException(msg); |
82 | 0 | } |
83 | 2.38M | } |
84 | | |
85 | | static bool isXInterface(typelib_TypeDescriptionReference const* pTypeLibType) |
86 | 2.38M | { |
87 | 2.38M | return OUString::unacquired(&pTypeLibType->pTypeName) == "com.sun.star.uno.XInterface"; |
88 | 2.38M | } |
89 | | |
90 | | static bool td_equals(typelib_TypeDescriptionReference const* pTDR1, |
91 | | typelib_TypeDescriptionReference const* pTDR2) |
92 | 8.63M | { |
93 | 8.63M | return ((pTDR1 == pTDR2) |
94 | 6.82M | || OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName)); |
95 | 8.63M | } |
96 | | |
97 | | static cppu::type_entry* getTypeEntries(cppu::class_data* cd) |
98 | 1.91M | { |
99 | 1.91M | cppu::type_entry* pEntries = cd->m_typeEntries; |
100 | 1.91M | if (!cd->m_storedTypeRefs) // not inited? |
101 | 97 | { |
102 | 97 | static std::mutex aMutex; |
103 | 97 | std::scoped_lock guard(aMutex); |
104 | 97 | if (!cd->m_storedTypeRefs) // not inited? |
105 | 97 | { |
106 | | // get all types |
107 | 625 | for (sal_Int32 n = cd->m_nTypes; n--;) |
108 | 528 | { |
109 | 528 | cppu::type_entry* pEntry = &pEntries[n]; |
110 | 528 | css::uno::Type const& rType = (*pEntry->m_type.getCppuType)(nullptr); |
111 | 528 | OSL_ENSURE(rType.getTypeClass() == css::uno::TypeClass_INTERFACE, |
112 | 528 | "### wrong helper init: expected interface!"); |
113 | 528 | OSL_ENSURE( |
114 | 528 | !isXInterface(rType.getTypeLibType()), |
115 | 528 | "### want to implement XInterface: template argument is XInterface?!?!?!"); |
116 | 528 | if (rType.getTypeClass() != css::uno::TypeClass_INTERFACE) |
117 | 0 | { |
118 | 0 | OUString msg("type \"" + rType.getTypeName() + "\" is no interface type!"); |
119 | 0 | SAL_WARN("cppuhelper", msg); |
120 | 0 | throw css::uno::RuntimeException(msg); |
121 | 0 | } |
122 | | // ref is statically held by getCppuType() |
123 | 528 | pEntry->m_type.typeRef = rType.getTypeLibType(); |
124 | 528 | } |
125 | 97 | OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); |
126 | 97 | cd->m_storedTypeRefs = true; |
127 | 97 | } |
128 | 97 | } |
129 | 1.91M | else |
130 | 1.91M | { |
131 | 1.91M | OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); |
132 | 1.91M | } |
133 | 1.91M | return pEntries; |
134 | 1.91M | } |
135 | | |
136 | | static void* makeInterface(sal_IntPtr nOffset, void* that) |
137 | 1.80M | { |
138 | 1.80M | return (static_cast<char*>(that) + nOffset); |
139 | 1.80M | } |
140 | | |
141 | | static bool recursivelyFindType(typelib_TypeDescriptionReference const* demandedType, |
142 | | typelib_InterfaceTypeDescription const* type, sal_IntPtr* offset) |
143 | 1.81M | { |
144 | | // This code assumes that the vtables of a multiple-inheritance class (the |
145 | | // offset amount by which to adjust the this pointer) follow one another in |
146 | | // the object layout, and that they contain slots for the inherited classes |
147 | | // in a specific order. In theory, that need not hold for any given |
148 | | // platform; in practice, it seems to work well on all supported platforms: |
149 | 2.13M | next: |
150 | 3.61M | for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) |
151 | 2.14M | { |
152 | 2.14M | if (i > 0) |
153 | 5.33k | { |
154 | 5.33k | *offset += sizeof(void*); |
155 | 5.33k | } |
156 | 2.14M | typelib_InterfaceTypeDescription const* base = type->ppBaseTypes[i]; |
157 | | // ignore XInterface: |
158 | 2.14M | if (base->nBaseTypes > 0) |
159 | 669k | { |
160 | 669k | if (td_equals(reinterpret_cast<typelib_TypeDescriptionReference const*>(base), |
161 | 669k | demandedType)) |
162 | 348k | { |
163 | 348k | return true; |
164 | 348k | } |
165 | | // Profiling showed that it is important to speed up the common case |
166 | | // of only one base: |
167 | 320k | if (type->nBaseTypes == 1) |
168 | 315k | { |
169 | 315k | type = base; |
170 | 315k | goto next; |
171 | 315k | } |
172 | 5.34k | if (recursivelyFindType(demandedType, base, offset)) |
173 | 6 | { |
174 | 6 | return true; |
175 | 6 | } |
176 | 5.34k | } |
177 | 2.14M | } |
178 | 1.47M | return false; |
179 | 2.13M | } |
180 | | |
181 | | static void* queryDeepNoXInterface(typelib_TypeDescriptionReference const* pDemandedTDR, |
182 | | cppu::class_data* cd, void* that) |
183 | 2.38M | { |
184 | 2.38M | if (isXInterface(pDemandedTDR)) |
185 | 470k | return nullptr; |
186 | | |
187 | 1.91M | cppu::type_entry* pEntries = getTypeEntries(cd); |
188 | 1.91M | sal_Int32 nTypes = cd->m_nTypes; |
189 | 1.91M | sal_Int32 n; |
190 | | |
191 | | // try top interfaces without getting td |
192 | 8.42M | for (n = 0; n < nTypes; ++n) |
193 | 7.96M | { |
194 | 7.96M | if (td_equals(pEntries[n].m_type.typeRef, pDemandedTDR)) |
195 | 1.45M | { |
196 | 1.45M | return makeInterface(pEntries[n].m_offset, that); |
197 | 1.45M | } |
198 | 7.96M | } |
199 | | // query deep getting td |
200 | 1.93M | for (n = 0; n < nTypes; ++n) |
201 | 1.81M | { |
202 | 1.81M | typelib_TypeDescription* pTD = nullptr; |
203 | 1.81M | TYPELIB_DANGER_GET(&pTD, pEntries[n].m_type.typeRef); |
204 | 1.81M | if (pTD) |
205 | 1.81M | { |
206 | | // exclude top (already tested) and bottom (XInterface) interface |
207 | 1.81M | OSL_ENSURE(reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD)->nBaseTypes > 0, |
208 | 1.81M | "### want to implement XInterface:" |
209 | 1.81M | " template argument is XInterface?!?!?!"); |
210 | 1.81M | sal_IntPtr offset = pEntries[n].m_offset; |
211 | 1.81M | bool found = recursivelyFindType( |
212 | 1.81M | pDemandedTDR, reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD), &offset); |
213 | 1.81M | TYPELIB_DANGER_RELEASE(pTD); |
214 | 1.81M | if (found) |
215 | 348k | { |
216 | 348k | return makeInterface(offset, that); |
217 | 348k | } |
218 | 1.81M | } |
219 | 0 | else |
220 | 0 | { |
221 | 0 | OUString msg("cannot get type description for type \"" |
222 | 0 | + OUString::unacquired(&pEntries[n].m_type.typeRef->pTypeName) + "\"!"); |
223 | 0 | SAL_WARN("cppuhelper", msg); |
224 | 0 | throw css::uno::RuntimeException(msg); |
225 | 0 | } |
226 | 1.81M | } |
227 | 115k | return nullptr; |
228 | 464k | } |
229 | | |
230 | | css::uno::Any WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd, |
231 | | WeakComponentImplHelperBase* pBase) |
232 | 908k | { |
233 | 908k | checkInterface(rType); |
234 | 908k | typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType(); |
235 | | |
236 | | // shortcut XInterface to WeakComponentImplHelperBase |
237 | 908k | if (void* p = queryDeepNoXInterface(pTDR, cd, pBase)) |
238 | 796k | return css::uno::Any(&p, pTDR); |
239 | 112k | return pBase->comphelper::WeakComponentImplHelperBase::queryInterface(rType); |
240 | 908k | } |
241 | | |
242 | 300k | WeakImplHelperBase::~WeakImplHelperBase() {} |
243 | | |
244 | | css::uno::Any WeakImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd, |
245 | | WeakImplHelperBase* pBase) |
246 | 1.47M | { |
247 | 1.47M | checkInterface(rType); |
248 | 1.47M | typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType(); |
249 | | |
250 | | // shortcut XInterface to WeakImplHelperBase |
251 | 1.47M | if (void* p = queryDeepNoXInterface(pTDR, cd, pBase)) |
252 | 1.00M | return css::uno::Any(&p, pTDR); |
253 | 474k | return pBase->comphelper::WeakImplHelperBase::queryInterface(rType); |
254 | 1.47M | } |
255 | | |
256 | | } // namespace comphelper |
257 | | |
258 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |