2024-06-12 13:20:46 +02:00
|
|
|
/* -*- Mode: JS; 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/.
|
|
|
|
*/
|
|
|
|
|
2024-07-12 09:30:18 +02:00
|
|
|
Module.unoTagSymbol = Symbol('unoTag');
|
|
|
|
|
2024-07-18 11:44:45 +02:00
|
|
|
Module.uno_init = new Promise(function (resolve, reject) {
|
|
|
|
Module.uno_init$resolve = function() {
|
2024-07-12 09:30:18 +02:00
|
|
|
Module.uno = init_unoembind_uno(Module, Module.unoTagSymbol);
|
2024-07-18 11:44:45 +02:00
|
|
|
resolve();
|
|
|
|
};
|
|
|
|
Module.uno_init$reject = reject;
|
|
|
|
});
|
2024-06-12 13:20:46 +02:00
|
|
|
|
2024-08-15 15:18:29 +02:00
|
|
|
Module.uno_main = new Promise(function (resolve, reject) {
|
|
|
|
Module.uno_main$resolve = resolve;
|
|
|
|
Module.uno_main$reject = reject;
|
|
|
|
});
|
|
|
|
|
2024-06-21 09:58:07 +02:00
|
|
|
Module.catchUnoException = function(exception) {
|
|
|
|
// Rethrow non-C++ exceptions (non-UNO C++ exceptions are mapped to css.uno.RuntimeException in
|
|
|
|
// Module.getUnoExceptionFromCxaException):
|
|
|
|
if (!(exception instanceof WebAssembly.Exception && exception.is(getCppExceptionTag()))) {
|
|
|
|
throw exception;
|
|
|
|
}
|
|
|
|
const any = Module.getUnoExceptionFromCxaException(
|
|
|
|
getCppExceptionThrownObjectFromWebAssemblyException(exception));
|
|
|
|
decrementExceptionRefcount(exception);
|
|
|
|
return any;
|
|
|
|
}
|
|
|
|
|
2024-06-12 13:20:46 +02:00
|
|
|
Module.unoObject = function(interfaces, obj) {
|
|
|
|
interfaces = ['com.sun.star.lang.XTypeProvider'].concat(interfaces);
|
|
|
|
obj.impl_refcount = 0;
|
|
|
|
obj.queryInterface = function(type) {
|
2024-06-12 14:54:06 +02:00
|
|
|
for (const i in obj.impl_typemap) {
|
2024-06-12 13:20:46 +02:00
|
|
|
if (i === type.toString()) {
|
2024-09-02 08:48:21 +02:00
|
|
|
const ifc = Module['uno_Type_' + i.replace(/\./g, '$')].reference(
|
|
|
|
obj.impl_interfaces[obj.impl_typemap[i]]);
|
|
|
|
try {
|
|
|
|
return new Module.uno_Any(type, ifc);
|
|
|
|
} finally {
|
|
|
|
ifc.delete();
|
|
|
|
}
|
2024-06-12 13:20:46 +02:00
|
|
|
}
|
|
|
|
}
|
2024-08-30 16:19:10 +02:00
|
|
|
const ty = Module.uno_Type.Void();
|
|
|
|
const ret = new Module.uno_Any(ty, undefined);
|
|
|
|
ty.delete();
|
|
|
|
return ret;
|
2024-06-12 13:20:46 +02:00
|
|
|
};
|
|
|
|
obj.acquire = function() { ++obj.impl_refcount; };
|
|
|
|
obj.release = function() {
|
|
|
|
if (--obj.impl_refcount === 0) {
|
2024-06-12 14:54:06 +02:00
|
|
|
for (const i in obj.impl_interfaces) {
|
2024-06-17 13:50:11 +02:00
|
|
|
obj.impl_interfaces[i].delete();
|
2024-06-12 13:20:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
Embind: Fix lifecycle of UNO any and sequence values returned from JS to C++
When a JS function implementing a UNO interface method returns any or a sequence
type (like queryInterface, getType, and getImplementationId in uno.js), it
could not create a new instance of that type and return it, as it would have
needed to call .delete() on that instance, but couldn't. In uno.js, getType and
getImplementationId solved that by returning pre-instantiated instances that
were deleted in the final release call. But that did not work for
queryInterface, as pre-instantiating the relevant any instances would have
caused cyclic references that would have caused the final release call never to
occur.
So redesign the C++ the_wrapper classes (used by the Embind allow_subclass
machinery): If a UNO interface method returns any or a sequence type (i.e., a
type on which .delete() must be called), change the JS implemenation's return
type from by-value (which meant that the C++ code received a copy) to
by-reference---which means that now the C++ code can access the original
instance and delete it. But which also means that the JS code must always
return a fresh instance now!
(Ideally, the embindmaker-generated code would use by-pointer rather than
by-reference for that return type, but that caused
> emsdk/upstream/emscripten/cache/sysroot/include/emscripten/wire.h:116:19: error: static assertion failed due to requirement '!std::is_pointer<com::sun::star::uno::Any *>::value': Implicitly binding raw pointers is illegal. Specify allow_raw_pointer<arg<?>>
> 116 | static_assert(!std::is_pointer<T*>::value, "Implicitly binding raw pointers is illegal. Specify allow_raw_pointer<arg<?>>");
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~
errors with no obvious place where to put such allow_raw_pointer markers, so
lets go with this little hack at least for now.)
Change-Id: I3c37b79b8fbf09c19782c6532bc95d4d63505c63
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169008
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
2024-06-17 15:54:43 +02:00
|
|
|
obj.getTypes = function() {
|
|
|
|
const types = new Module.uno_Sequence_type(interfaces.length, Module.uno_Sequence.FromSize);
|
|
|
|
for (let i = 0; i !== interfaces.length; ++i) {
|
2024-08-30 16:19:10 +02:00
|
|
|
const type = Module.uno_Type.Interface(interfaces[i]);
|
|
|
|
types.set(i, type);
|
|
|
|
type.delete();
|
Embind: Fix lifecycle of UNO any and sequence values returned from JS to C++
When a JS function implementing a UNO interface method returns any or a sequence
type (like queryInterface, getType, and getImplementationId in uno.js), it
could not create a new instance of that type and return it, as it would have
needed to call .delete() on that instance, but couldn't. In uno.js, getType and
getImplementationId solved that by returning pre-instantiated instances that
were deleted in the final release call. But that did not work for
queryInterface, as pre-instantiating the relevant any instances would have
caused cyclic references that would have caused the final release call never to
occur.
So redesign the C++ the_wrapper classes (used by the Embind allow_subclass
machinery): If a UNO interface method returns any or a sequence type (i.e., a
type on which .delete() must be called), change the JS implemenation's return
type from by-value (which meant that the C++ code received a copy) to
by-reference---which means that now the C++ code can access the original
instance and delete it. But which also means that the JS code must always
return a fresh instance now!
(Ideally, the embindmaker-generated code would use by-pointer rather than
by-reference for that return type, but that caused
> emsdk/upstream/emscripten/cache/sysroot/include/emscripten/wire.h:116:19: error: static assertion failed due to requirement '!std::is_pointer<com::sun::star::uno::Any *>::value': Implicitly binding raw pointers is illegal. Specify allow_raw_pointer<arg<?>>
> 116 | static_assert(!std::is_pointer<T*>::value, "Implicitly binding raw pointers is illegal. Specify allow_raw_pointer<arg<?>>");
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~
errors with no obvious place where to put such allow_raw_pointer markers, so
lets go with this little hack at least for now.)
Change-Id: I3c37b79b8fbf09c19782c6532bc95d4d63505c63
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169008
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
2024-06-17 15:54:43 +02:00
|
|
|
}
|
|
|
|
return types;
|
|
|
|
};
|
|
|
|
obj.getImplementationId = function() { return new Module.uno_Sequence_byte([]) };
|
2024-06-12 14:54:06 +02:00
|
|
|
obj.impl_interfaces = {};
|
2024-06-12 13:20:46 +02:00
|
|
|
interfaces.forEach((i) => {
|
2024-06-12 14:54:06 +02:00
|
|
|
obj.impl_interfaces[i] = Module['uno_Type_' + i.replace(/\./g, '$')].implement(obj);
|
2024-06-12 13:20:46 +02:00
|
|
|
});
|
2024-06-12 14:54:06 +02:00
|
|
|
obj.impl_typemap = {};
|
2024-06-12 13:20:46 +02:00
|
|
|
const walk = function(td, impl) {
|
|
|
|
const name = td.getName();
|
2024-06-12 14:54:06 +02:00
|
|
|
if (!Object.hasOwn(obj.impl_typemap, name)) {
|
2024-06-12 13:20:46 +02:00
|
|
|
if (td.getTypeClass() != Module.uno.com.sun.star.uno.TypeClass.INTERFACE) {
|
|
|
|
throw new Error('not a UNO interface type: ' + name);
|
|
|
|
}
|
2024-06-12 14:54:06 +02:00
|
|
|
obj.impl_typemap[name] = impl;
|
2024-08-30 16:19:10 +02:00
|
|
|
const itd = Module.uno.com.sun.star.reflection.XInterfaceTypeDescription2.query(td);
|
|
|
|
const bases = itd.getBaseTypes();
|
|
|
|
itd.delete();
|
2024-06-12 13:20:46 +02:00
|
|
|
for (let i = 0; i !== bases.size(); ++i) {
|
2024-08-30 16:24:43 +02:00
|
|
|
walk(bases.get(i), impl);
|
2024-06-12 13:20:46 +02:00
|
|
|
}
|
|
|
|
bases.delete();
|
|
|
|
}
|
2024-08-30 16:19:10 +02:00
|
|
|
td.delete();
|
2024-06-12 13:20:46 +02:00
|
|
|
};
|
2024-08-30 16:19:10 +02:00
|
|
|
const ctx = Module.getUnoComponentContext();
|
|
|
|
const tdmAny = ctx.getValueByName(
|
2024-06-12 13:20:46 +02:00
|
|
|
'/singletons/com.sun.star.reflection.theTypeDescriptionManager');
|
2024-08-30 16:19:10 +02:00
|
|
|
ctx.delete();
|
|
|
|
const ifc = tdmAny.get();
|
|
|
|
tdmAny.delete();
|
|
|
|
const tdm = Module.uno.com.sun.star.container.XHierarchicalNameAccess.query(ifc);
|
|
|
|
ifc.delete();
|
2024-06-12 13:20:46 +02:00
|
|
|
interfaces.forEach((i) => {
|
|
|
|
const td = tdm.getByHierarchicalName(i);
|
2024-08-30 16:19:10 +02:00
|
|
|
const ifc = td.get();
|
2024-06-12 13:20:46 +02:00
|
|
|
td.delete();
|
2024-08-30 16:19:10 +02:00
|
|
|
walk(Module.uno.com.sun.star.reflection.XTypeDescription.query(ifc), i);
|
|
|
|
ifc.delete();
|
2024-06-12 13:20:46 +02:00
|
|
|
})
|
2024-08-30 16:19:10 +02:00
|
|
|
tdm.delete();
|
2024-06-12 14:54:06 +02:00
|
|
|
return Module.uno.com.sun.star.uno.XInterface.reference(
|
|
|
|
obj.impl_interfaces[obj.impl_typemap['com.sun.star.uno.XInterface']]);
|
2024-06-12 13:20:46 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|