/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 | 290k | WeakComponentImplHelperBase::~WeakComponentImplHelperBase() {} |
18 | | |
19 | | // css::lang::XComponent |
20 | | void SAL_CALL WeakComponentImplHelperBase::dispose() |
21 | 20.8k | { |
22 | 20.8k | std::unique_lock aGuard(m_aMutex); |
23 | 20.8k | if (m_bDisposed) |
24 | 0 | return; |
25 | 20.8k | m_bDisposed = true; |
26 | 20.8k | disposing(aGuard); |
27 | 20.8k | if (!aGuard.owns_lock()) |
28 | 0 | aGuard.lock(); |
29 | 20.8k | css::lang::EventObject aEvt(static_cast<OWeakObject*>(this)); |
30 | 20.8k | maEventListeners.disposeAndClear(aGuard, aEvt); |
31 | 20.8k | } |
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 | 13.9k | 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 | 32.3k | { |
53 | 32.3k | std::unique_lock aGuard(m_aMutex); |
54 | 32.3k | if (m_bDisposed) |
55 | 0 | return; |
56 | 32.3k | maEventListeners.addInterface(aGuard, rxListener); |
57 | 32.3k | } |
58 | | |
59 | | void SAL_CALL WeakComponentImplHelperBase::removeEventListener( |
60 | | css::uno::Reference<css::lang::XEventListener> const& rxListener) |
61 | 17.5k | { |
62 | 17.5k | std::unique_lock aGuard(m_aMutex); |
63 | 17.5k | maEventListeners.removeInterface(aGuard, rxListener); |
64 | 17.5k | } |
65 | | |
66 | | css::uno::Any SAL_CALL WeakComponentImplHelperBase::queryInterface(css::uno::Type const& rType) |
67 | 41.7k | { |
68 | 41.7k | css::uno::Any aReturn = ::cppu::queryInterface(rType, static_cast<css::uno::XWeak*>(this), |
69 | 41.7k | static_cast<css::lang::XComponent*>(this)); |
70 | 41.7k | if (aReturn.hasValue()) |
71 | 11.3k | return aReturn; |
72 | 30.3k | return OWeakObject::queryInterface(rType); |
73 | 41.7k | } |
74 | | |
75 | | static void checkInterface(css::uno::Type const& rType) |
76 | 1.47M | { |
77 | 1.47M | 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 | 1.47M | } |
84 | | |
85 | | static bool isXInterface(typelib_TypeDescriptionReference const* pTypeLibType) |
86 | 1.47M | { |
87 | 1.47M | return OUString::unacquired(&pTypeLibType->pTypeName) == "com.sun.star.uno.XInterface"; |
88 | 1.47M | } |
89 | | |
90 | | static bool td_equals(typelib_TypeDescriptionReference const* pTDR1, |
91 | | typelib_TypeDescriptionReference const* pTDR2) |
92 | 5.09M | { |
93 | 5.09M | return ((pTDR1 == pTDR2) |
94 | 3.98M | || OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName)); |
95 | 5.09M | } |
96 | | |
97 | | static cppu::type_entry* getTypeEntries(cppu::class_data* cd) |
98 | 1.15M | { |
99 | 1.15M | cppu::type_entry* pEntries = cd->m_typeEntries; |
100 | 1.15M | if (!cd->m_storedTypeRefs) // not inited? |
101 | 93 | { |
102 | 93 | static std::mutex aMutex; |
103 | 93 | std::scoped_lock guard(aMutex); |
104 | 93 | if (!cd->m_storedTypeRefs) // not inited? |
105 | 93 | { |
106 | | // get all types |
107 | 593 | for (sal_Int32 n = cd->m_nTypes; n--;) |
108 | 500 | { |
109 | 500 | cppu::type_entry* pEntry = &pEntries[n]; |
110 | 500 | css::uno::Type const& rType = (*pEntry->m_type.getCppuType)(nullptr); |
111 | 500 | OSL_ENSURE(rType.getTypeClass() == css::uno::TypeClass_INTERFACE, |
112 | 500 | "### wrong helper init: expected interface!"); |
113 | 500 | OSL_ENSURE( |
114 | 500 | !isXInterface(rType.getTypeLibType()), |
115 | 500 | "### want to implement XInterface: template argument is XInterface?!?!?!"); |
116 | 500 | 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 | 500 | pEntry->m_type.typeRef = rType.getTypeLibType(); |
124 | 500 | } |
125 | 93 | OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); |
126 | 93 | cd->m_storedTypeRefs = true; |
127 | 93 | } |
128 | 93 | } |
129 | 1.15M | else |
130 | 1.15M | { |
131 | 1.15M | OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); |
132 | 1.15M | } |
133 | 1.15M | return pEntries; |
134 | 1.15M | } |
135 | | |
136 | | static void* makeInterface(sal_IntPtr nOffset, void* that) |
137 | 1.11M | { |
138 | 1.11M | return (static_cast<char*>(that) + nOffset); |
139 | 1.11M | } |
140 | | |
141 | | static bool recursivelyFindType(typelib_TypeDescriptionReference const* demandedType, |
142 | | typelib_InterfaceTypeDescription const* type, sal_IntPtr* offset) |
143 | 871k | { |
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 | 1.09M | next: |
150 | 1.70M | for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) |
151 | 1.09M | { |
152 | 1.09M | if (i > 0) |
153 | 3.64k | { |
154 | 3.64k | *offset += sizeof(void*); |
155 | 3.64k | } |
156 | 1.09M | typelib_InterfaceTypeDescription const* base = type->ppBaseTypes[i]; |
157 | | // ignore XInterface: |
158 | 1.09M | if (base->nBaseTypes > 0) |
159 | 489k | { |
160 | 489k | if (td_equals(reinterpret_cast<typelib_TypeDescriptionReference const*>(base), |
161 | 489k | demandedType)) |
162 | 265k | { |
163 | 265k | return true; |
164 | 265k | } |
165 | | // Profiling showed that it is important to speed up the common case |
166 | | // of only one base: |
167 | 224k | if (type->nBaseTypes == 1) |
168 | 220k | { |
169 | 220k | type = base; |
170 | 220k | goto next; |
171 | 220k | } |
172 | 3.64k | if (recursivelyFindType(demandedType, base, offset)) |
173 | 6 | { |
174 | 6 | return true; |
175 | 6 | } |
176 | 3.64k | } |
177 | 1.09M | } |
178 | 605k | return false; |
179 | 1.09M | } |
180 | | |
181 | | static void* queryDeepNoXInterface(typelib_TypeDescriptionReference const* pDemandedTDR, |
182 | | cppu::class_data* cd, void* that) |
183 | 1.47M | { |
184 | 1.47M | if (isXInterface(pDemandedTDR)) |
185 | 320k | return nullptr; |
186 | | |
187 | 1.15M | cppu::type_entry* pEntries = getTypeEntries(cd); |
188 | 1.15M | sal_Int32 nTypes = cd->m_nTypes; |
189 | 1.15M | sal_Int32 n; |
190 | | |
191 | | // try top interfaces without getting td |
192 | 4.91M | for (n = 0; n < nTypes; ++n) |
193 | 4.61M | { |
194 | 4.61M | if (td_equals(pEntries[n].m_type.typeRef, pDemandedTDR)) |
195 | 846k | { |
196 | 846k | return makeInterface(pEntries[n].m_offset, that); |
197 | 846k | } |
198 | 4.61M | } |
199 | | // query deep getting td |
200 | 908k | for (n = 0; n < nTypes; ++n) |
201 | 867k | { |
202 | 867k | typelib_TypeDescription* pTD = nullptr; |
203 | 867k | TYPELIB_DANGER_GET(&pTD, pEntries[n].m_type.typeRef); |
204 | 867k | if (pTD) |
205 | 867k | { |
206 | | // exclude top (already tested) and bottom (XInterface) interface |
207 | 867k | OSL_ENSURE(reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD)->nBaseTypes > 0, |
208 | 867k | "### want to implement XInterface:" |
209 | 867k | " template argument is XInterface?!?!?!"); |
210 | 867k | sal_IntPtr offset = pEntries[n].m_offset; |
211 | 867k | bool found = recursivelyFindType( |
212 | 867k | pDemandedTDR, reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD), &offset); |
213 | 867k | TYPELIB_DANGER_RELEASE(pTD); |
214 | 867k | if (found) |
215 | 265k | { |
216 | 265k | return makeInterface(offset, that); |
217 | 265k | } |
218 | 867k | } |
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 | 867k | } |
227 | 41.0k | return nullptr; |
228 | 306k | } |
229 | | |
230 | | css::uno::Any WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd, |
231 | | WeakComponentImplHelperBase* pBase) |
232 | 516k | { |
233 | 516k | checkInterface(rType); |
234 | 516k | typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType(); |
235 | | |
236 | | // shortcut XInterface to WeakComponentImplHelperBase |
237 | 516k | if (void* p = queryDeepNoXInterface(pTDR, cd, pBase)) |
238 | 475k | return css::uno::Any(&p, pTDR); |
239 | 41.7k | return pBase->comphelper::WeakComponentImplHelperBase::queryInterface(rType); |
240 | 516k | } |
241 | | |
242 | 108k | WeakImplHelperBase::~WeakImplHelperBase() {} |
243 | | |
244 | | css::uno::Any WeakImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd, |
245 | | WeakImplHelperBase* pBase) |
246 | 956k | { |
247 | 956k | checkInterface(rType); |
248 | 956k | typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType(); |
249 | | |
250 | | // shortcut XInterface to WeakImplHelperBase |
251 | 956k | if (void* p = queryDeepNoXInterface(pTDR, cd, pBase)) |
252 | 636k | return css::uno::Any(&p, pTDR); |
253 | 319k | return pBase->comphelper::WeakImplHelperBase::queryInterface(rType); |
254 | 956k | } |
255 | | |
256 | | } // namespace comphelper |
257 | | |
258 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |