1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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/.
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>
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
),
60 Module
.registerType(raw
, {
63 let str
= String
.fromCharCode(Module
.HEAPU16
[ptr
>> 1]);
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
);
79 readValueFromPointer(pointer
) {
80 return this.fromWireType(Module
.HEAPU32
[((pointer
)>>2)]);
82 destructorFunction(ptr
) {
90 #pragma clang diagnostic push
91 #pragma clang diagnostic ignored "-Winvalid-pp-token"
92 EM_JS(void, jsRegisterString
, (std::type_info
const* raw
),
95 Module
.registerType(raw
, {
96 name
: 'rtl::OUString',
98 let data
= Module
.HEAPU32
[ptr
>> 2];
99 let length
= Module
.HEAPU32
[(data
>> 2) + 1];
100 let buffer
= data
+ 8;
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
);
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
);
130 readValueFromPointer(pointer
) {
131 return this.fromWireType(Module
.HEAPU32
[((pointer
)>>2)]);
133 destructorFunction(ptr
) {
140 #pragma clang diagnostic pop
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
)
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();
173 return pSh
->GetCurrentDocument();
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");
196 Any
constructAny(const css::uno::Type
& rUnoType
, const val
& rObject
)
198 switch (rUnoType
.getTypeClass())
202 case TypeClass_BOOLEAN
:
203 return Any
{ rObject
.as
<bool>() };
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
>() };
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>() };
223 return Any
{ rObject
.as
<char16_t
>() };
224 case TypeClass_STRING
:
225 return Any
{ OUString(rObject
.as
<std::u16string
>()) };
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
),
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
)),
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());
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());
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
;
378 emscripten::internal::WireTypePack
argv(std::move(copy
));
379 return emscripten::val::take_ownership(
380 _emval_take_value(getTypeId(self
.getValueType()), argv
));
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
));
412 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */