Embind: throwUnoException from JS
[LibreOffice.git] / static / source / unoembindhelpers / PrimaryBindings.cxx
blob7abf88669d020e74fd9d567d0fe59a166976fd29
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.
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 #ifdef EMSCRIPTEN
10 #include <com/sun/star/frame/XModel.hpp>
12 #include <emscripten.h>
13 #include <emscripten/bind.h>
15 #include <com/sun/star/uno/Any.hxx>
16 #include <com/sun/star/uno/RuntimeException.hpp>
17 #include <com/sun/star/uno/Type.hxx>
18 #include <comphelper/processfactory.hxx>
19 #include <cppuhelper/exc_hlp.hxx>
20 #include <o3tl/any.hxx>
21 #include <o3tl/temporary.hxx>
22 #include <o3tl/unreachable.hxx>
23 #include <rtl/ustring.hxx>
24 #include <sal/log.hxx>
25 #include <sfx2/viewsh.hxx>
26 #include <static/unoembindhelpers/PrimaryBindings.hxx>
27 #include <typelib/typedescription.h>
28 #include <typelib/typedescription.hxx>
29 #include <uno/data.h>
31 #include <cassert>
32 #include <cstdint>
33 #include <stdexcept>
34 #include <string>
35 #include <typeinfo>
36 #include <utility>
38 using namespace emscripten;
39 using namespace css::uno;
41 template <> struct emscripten::smart_ptr_trait<css::uno::Type>
43 using PointerType = css::uno::Type;
44 using element_type = typelib_TypeDescriptionReference;
45 static typelib_TypeDescriptionReference* get(css::uno::Type const& ptr)
47 return ptr.getTypeLibType();
49 static sharing_policy get_sharing_policy() { return sharing_policy::NONE; }
50 static css::uno::Type* share(typelib_TypeDescriptionReference* v)
52 return new css::uno::Type(v);
54 static css::uno::Type* construct_null() { return new css::uno::Type(); }
57 EM_JS(void, jsRegisterChar, (std::type_info const* raw),
58 // clang-format off
60 Module.registerType(raw, {
61 name: 'sal_Unicode',
62 fromWireType(ptr) {
63 let str = String.fromCharCode(Module.HEAPU16[ptr >> 1]);
64 return str;
66 toWireType(destructors, value) {
67 if (typeof value != 'string' || value.length !== 1) {
68 Module.throwBindingError(
69 'Cannot pass anything but 1-element string to C++ char16_t');
71 let data = Module._malloc(2);
72 Module.HEAPU16[data >> 1] = value.charCodeAt(0);
73 if (destructors !== null) {
74 destructors.push(Module._free, data);
76 return data;
78 argPackAdvance: 8,
79 readValueFromPointer(pointer) {
80 return this.fromWireType(Module.HEAPU32[((pointer)>>2)]);
82 destructorFunction(ptr) {
83 Module._free(ptr);
85 });
87 // clang-format on
90 #pragma clang diagnostic push
91 #pragma clang diagnostic ignored "-Winvalid-pp-token"
92 EM_JS(void, jsRegisterString, (std::type_info const* raw),
93 // clang-format off
95 Module.registerType(raw, {
96 name: 'rtl::OUString',
97 fromWireType(ptr) {
98 let data = Module.HEAPU32[ptr >> 2];
99 let length = Module.HEAPU32[(data >> 2) + 1];
100 let buffer = data + 8;
101 let str = '';
102 for (let i = 0; i < length; ++i) {
103 let c = Module.HEAPU16[(buffer >> 1) + i];
104 str += String.fromCharCode(c);
106 Module.rtl_uString_release(data);
107 Module._free(ptr);
108 return str;
110 toWireType(destructors, value) {
111 if (typeof value != 'string') {
112 Module.throwBindingError('Cannot pass non-string to C++ OUString');
114 let data = Module._malloc(8 + (value.length + 1) * 2);
115 Module.HEAPU32[data >> 2] = 1;
116 Module.HEAPU32[(data >> 2) + 1] = value.length;
117 let buffer = data + 8;
118 for (let i = 0; i < value.length; ++i) {
119 Module.HEAPU16[(buffer >> 1) + i] = value.charCodeAt(i);
121 Module.HEAPU16[(buffer >> 1) + value.length] = 0;
122 let ptr = Module._malloc(4);
123 Module.HEAPU32[ptr >> 2] = data;
124 if (destructors !== null) {
125 destructors.push(Module._free, ptr);
127 return ptr;
129 argPackAdvance: 8,
130 readValueFromPointer(pointer) {
131 return this.fromWireType(Module.HEAPU32[((pointer)>>2)]);
133 destructorFunction(ptr) {
134 Module._free(ptr);
138 // clang-format on
140 #pragma clang diagnostic pop
142 namespace
144 void copyStruct(typelib_CompoundTypeDescription* desc, void const* source, void* dest)
146 if (desc->pBaseTypeDescription != nullptr)
148 copyStruct(desc->pBaseTypeDescription, source, dest);
150 for (sal_Int32 i = 0; i != desc->nMembers; ++i)
152 uno_type_copyData(
153 static_cast<char*>(dest) + desc->pMemberOffsets[i],
154 const_cast<char*>(static_cast<char const*>(source) + desc->pMemberOffsets[i]),
155 desc->ppTypeRefs[i], cpp_acquire);
159 template <typename T> void registerInOutParam(char const* name)
161 class_<unoembindhelpers::UnoInOutParam<T>>(name).constructor().constructor<T>().property(
162 "val", &unoembindhelpers::UnoInOutParam<T>::get, &unoembindhelpers::UnoInOutParam<T>::set);
165 Reference<css::frame::XModel> getCurrentModelFromViewSh()
167 SfxViewShell* pSh = nullptr;
168 pSh = SfxViewShell::Current();
169 if (!pSh)
171 return {};
173 return pSh->GetCurrentDocument();
176 struct LessType
178 bool operator()(css::uno::Type const& type1, css::uno::Type const& type2) const
180 return type1.getTypeLibType() < type2.getTypeLibType();
184 std::map<css::uno::Type, std::type_info const*, LessType> unoTypes;
186 std::type_info const* getTypeId(css::uno::Type const& type)
188 auto const i = unoTypes.find(type);
189 if (i == unoTypes.end())
191 throw std::runtime_error("unregistered UNO type");
193 return i->second;
196 Any constructAny(const css::uno::Type& rUnoType, const val& rObject)
198 switch (rUnoType.getTypeClass())
200 case TypeClass_VOID:
201 return {};
202 case TypeClass_BOOLEAN:
203 return Any{ rObject.as<bool>() };
204 case TypeClass_BYTE:
205 return Any{ rObject.as<sal_Int8>() };
206 case TypeClass_SHORT:
207 return Any{ rObject.as<sal_Int16>() };
208 case TypeClass_UNSIGNED_SHORT:
209 return Any{ rObject.as<sal_uInt16>() };
210 case TypeClass_LONG:
211 return Any{ rObject.as<sal_Int32>() };
212 case TypeClass_UNSIGNED_LONG:
213 return Any{ rObject.as<sal_uInt32>() };
214 case TypeClass_HYPER:
215 return Any{ rObject.as<sal_Int64>() };
216 case TypeClass_UNSIGNED_HYPER:
217 return Any{ rObject.as<sal_uInt64>() };
218 case TypeClass_FLOAT:
219 return Any{ rObject.as<float>() };
220 case TypeClass_DOUBLE:
221 return Any{ rObject.as<double>() };
222 case TypeClass_CHAR:
223 return Any{ rObject.as<char16_t>() };
224 case TypeClass_STRING:
225 return Any{ OUString(rObject.as<std::u16string>()) };
226 case TypeClass_TYPE:
227 return css::uno::Any(rObject.as<css::uno::Type>());
228 case TypeClass_SEQUENCE:
229 case TypeClass_STRUCT:
230 case TypeClass_EXCEPTION:
231 case TypeClass_INTERFACE:
233 emscripten::internal::EM_DESTRUCTORS destructors = nullptr;
234 emscripten::internal::EM_GENERIC_WIRE_TYPE result
235 = _emval_as(rObject.as_handle(), getTypeId(rUnoType), &destructors);
236 emscripten::internal::DestructorsRunner dr(destructors);
237 return css::uno::Any(emscripten::internal::fromGenericWireType<void const*>(result),
238 rUnoType);
240 case TypeClass_ENUM:
242 emscripten::internal::EM_DESTRUCTORS destructors = nullptr;
243 emscripten::internal::EM_GENERIC_WIRE_TYPE result
244 = _emval_as(rObject.as_handle(), getTypeId(rUnoType), &destructors);
245 emscripten::internal::DestructorsRunner dr(destructors);
246 return css::uno::Any(
247 &o3tl::temporary(emscripten::internal::fromGenericWireType<sal_Int32>(result)),
248 rUnoType);
250 default:
251 throw std::invalid_argument("bad type class");
256 namespace unoembindhelpers::detail
258 void registerUnoType(css::uno::Type const& type, std::type_info const* id) { unoTypes[type] = id; }
261 EMSCRIPTEN_BINDINGS(PrimaryBindings)
263 enum_<unoembindhelpers::uno_Sequence>("uno_Sequence")
264 .value("FromSize", unoembindhelpers::uno_Sequence::FromSize);
266 emscripten::class_<typelib_TypeDescriptionReference>("uno_Type")
267 .smart_ptr<css::uno::Type>("uno_Type$")
268 .class_function("Void", +[]() { return cppu::UnoType<void>::get(); })
269 .class_function("Boolean", +[]() { return cppu::UnoType<bool>::get(); })
270 .class_function("Byte", +[]() { return cppu::UnoType<sal_Int8>::get(); })
271 .class_function("Short", +[]() { return cppu::UnoType<sal_Int16>::get(); })
272 .class_function("UnsignedShort", +[]() { return cppu::UnoType<sal_uInt16>::get(); })
273 .class_function("Long", +[]() { return cppu::UnoType<sal_Int32>::get(); })
274 .class_function("UnsignedLong", +[]() { return cppu::UnoType<sal_uInt32>::get(); })
275 .class_function("Hyper", +[]() { return cppu::UnoType<sal_Int64>::get(); })
276 .class_function("UnsignedHyper", +[]() { return cppu::UnoType<sal_uInt64>::get(); })
277 .class_function("Float", +[]() { return cppu::UnoType<float>::get(); })
278 .class_function("Double", +[]() { return cppu::UnoType<double>::get(); })
279 .class_function("Char", +[]() { return cppu::UnoType<sal_Unicode>::get(); })
280 .class_function("String", +[]() { return cppu::UnoType<OUString>::get(); })
281 .class_function("Type", +[]() { return cppu::UnoType<css::uno::Type>::get(); })
282 .class_function("Any", +[]() { return cppu::UnoType<css::uno::Any>::get(); })
283 .class_function("Sequence",
284 +[](css::uno::Type const& type) {
285 return css::uno::Type(css::uno::TypeClass_SEQUENCE,
286 "[]" + type.getTypeName());
288 .class_function("Enum",
289 +[](std::u16string const& name) {
290 return css::uno::Type(css::uno::TypeClass_ENUM, OUString(name));
292 .class_function("Struct",
293 +[](std::u16string const& name) {
294 return css::uno::Type(css::uno::TypeClass_STRUCT, OUString(name));
296 .class_function("Exception",
297 +[](std::u16string const& name) {
298 return css::uno::Type(css::uno::TypeClass_EXCEPTION, OUString(name));
300 .class_function("Interface",
301 +[](std::u16string const& name) {
302 return css::uno::Type(css::uno::TypeClass_INTERFACE, OUString(name));
304 .function("toString", +[](css::uno::Type const& self) {
305 auto const name = self.getTypeName();
306 return std::u16string(name.getStr(), name.getLength());
309 // Any
310 class_<Any>("uno_Any")
311 .constructor(&constructAny)
312 .function("get", +[](css::uno::Any const& self) {
313 switch (self.getValueType().getTypeClass())
315 case css::uno::TypeClass_VOID:
316 return emscripten::val::undefined();
317 case css::uno::TypeClass_BOOLEAN:
318 return emscripten::val(*o3tl::forceAccess<bool>(self));
319 case css::uno::TypeClass_BYTE:
320 return emscripten::val(*o3tl::forceAccess<sal_Int8>(self));
321 case css::uno::TypeClass_SHORT:
322 return emscripten::val(*o3tl::forceAccess<sal_Int16>(self));
323 case css::uno::TypeClass_UNSIGNED_SHORT:
324 return emscripten::val(*o3tl::forceAccess<sal_uInt16>(self));
325 case css::uno::TypeClass_LONG:
326 return emscripten::val(*o3tl::forceAccess<sal_Int32>(self));
327 case css::uno::TypeClass_UNSIGNED_LONG:
328 return emscripten::val(*o3tl::forceAccess<sal_uInt32>(self));
329 case css::uno::TypeClass_HYPER:
330 return emscripten::val(*o3tl::forceAccess<sal_Int64>(self));
331 case css::uno::TypeClass_UNSIGNED_HYPER:
332 return emscripten::val(*o3tl::forceAccess<sal_uInt64>(self));
333 case css::uno::TypeClass_FLOAT:
334 return emscripten::val(*o3tl::forceAccess<float>(self));
335 case css::uno::TypeClass_DOUBLE:
336 return emscripten::val(*o3tl::forceAccess<double>(self));
337 case css::uno::TypeClass_CHAR:
338 return emscripten::val(*o3tl::forceAccess<sal_Unicode>(self));
339 case css::uno::TypeClass_STRING:
340 return emscripten::val(*o3tl::forceAccess<OUString>(self));
341 case css::uno::TypeClass_TYPE:
342 return emscripten::val(*o3tl::forceAccess<css::uno::Type>(self));
343 case css::uno::TypeClass_SEQUENCE:
345 auto const seq = *static_cast<uno_Sequence* const*>(self.getValue());
346 auto const copy = std::malloc(sizeof(uno_Sequence*));
347 *static_cast<uno_Sequence**>(copy) = seq;
348 osl_atomic_increment(&seq->nRefCount);
349 emscripten::internal::WireTypePack argv(std::move(copy));
350 return emscripten::val::take_ownership(
351 _emval_take_value(getTypeId(self.getValueType()), argv));
353 case css::uno::TypeClass_ENUM:
355 emscripten::internal::WireTypePack argv(
356 std::move(*static_cast<sal_Int32 const*>(self.getValue())));
357 return emscripten::val::take_ownership(
358 _emval_take_value(getTypeId(self.getValueType()), argv));
360 case css::uno::TypeClass_STRUCT:
361 case css::uno::TypeClass_EXCEPTION:
363 css::uno::TypeDescription desc(self.getValueType().getTypeLibType());
364 assert(desc.is());
365 auto const td = reinterpret_cast<typelib_CompoundTypeDescription*>(desc.get());
366 auto const copy = std::malloc(td->aBase.nSize);
367 copyStruct(td, self.getValue(), copy);
368 emscripten::internal::WireTypePack argv(std::move(copy));
369 return emscripten::val::take_ownership(
370 _emval_take_value(getTypeId(self.getValueType()), argv));
372 case css::uno::TypeClass_INTERFACE:
374 auto const ifc = *static_cast<css::uno::XInterface* const*>(self.getValue());
375 auto const copy = std::malloc(sizeof(css::uno::XInterface*));
376 *static_cast<css::uno::XInterface**>(copy) = ifc;
377 ifc->acquire();
378 emscripten::internal::WireTypePack argv(std::move(copy));
379 return emscripten::val::take_ownership(
380 _emval_take_value(getTypeId(self.getValueType()), argv));
382 default:
383 O3TL_UNREACHABLE;
387 registerInOutParam<bool>("uno_InOutParam_boolean");
388 registerInOutParam<sal_Int8>("uno_InOutParam_byte");
389 registerInOutParam<sal_Int16>("uno_InOutParam_short");
390 registerInOutParam<sal_uInt16>("uno_InOutParam_unsigned_short");
391 registerInOutParam<sal_Int32>("uno_InOutParam_long");
392 registerInOutParam<sal_uInt32>("uno_InOutParam_unsigned_long");
393 registerInOutParam<sal_Int64>("uno_InOutParam_hyper");
394 registerInOutParam<sal_uInt64>("uno_InOutParam_unsigned_hyper");
395 registerInOutParam<float>("uno_InOutParam_float");
396 registerInOutParam<double>("uno_InOutParam_double");
397 registerInOutParam<char16_t>("uno_InOutParam_char");
399 function("getCurrentModelFromViewSh", &getCurrentModelFromViewSh);
400 function("getUnoComponentContext", &comphelper::getProcessComponentContext);
401 function("throwUnoException", +[](css::uno::Type const& type, emscripten::val const& value) {
402 cppu::throwException(constructAny(type, value));
404 function("rtl_uString_release",
405 +[](std::uintptr_t ptr) { rtl_uString_release(reinterpret_cast<rtl_uString*>(ptr)); });
407 jsRegisterChar(&typeid(char16_t));
408 jsRegisterString(&typeid(OUString));
410 #endif
412 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */