summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--codemaker/source/cppumaker/cppuoptions.cxx18
-rw-r--r--codemaker/source/cppumaker/cpputype.cxx250
-rw-r--r--codemaker/source/cppumaker/cpputype.hxx9
-rw-r--r--codemaker/source/cppumaker/dumputils.cxx14
-rw-r--r--codemaker/source/cppumaker/dumputils.hxx3
-rw-r--r--codemaker/source/cppumaker/includes.cxx19
-rw-r--r--codemaker/source/cppumaker/includes.hxx5
-rw-r--r--desktop/Executable_soffice_bin.mk5
-rw-r--r--solenv/gbuild/UnoApi.mk17
-rw-r--r--solenv/gbuild/UnoApiTarget.mk18
-rw-r--r--solenv/gbuild/platform/unxgcc.mk14
-rw-r--r--static/README.wasm.md39
-rw-r--r--static/source/unoembindhelpers/PrimaryBindings.cxx121
13 files changed, 505 insertions, 27 deletions
diff --git a/codemaker/source/cppumaker/cppuoptions.cxx b/codemaker/source/cppumaker/cppuoptions.cxx
index 0a2ad962381a..f4ccf69b1ae7 100644
--- a/codemaker/source/cppumaker/cppuoptions.cxx
+++ b/codemaker/source/cppumaker/cppuoptions.cxx
@@ -216,6 +216,24 @@ bool CppuOptions::initOptions(int ac, char* av[], bool bCmdFile)
m_options["-G"] = OString();
break;
+ case 'W': // generate embind javascript bindings for LOWA
+ if (av[i][2] != '\0')
+ {
+ OString tmp("'-W', please check");
+ if (i <= ac - 1)
+ {
+ tmp += OString::Concat(" your input '") + av[i] + "'";
+ }
+
+ throw IllegalArgument(tmp);
+ }
+
+ if (!isValid("-C") && !isValid("-CS") && !isValid("-L"))
+ {
+ throw IllegalArgument("'-W' requires '-C' or '-CS' or '-L' option");
+ }
+ m_options["-W"] = OString();
+ break;
case 'X': // support for eXtra type rdbs
{
if (av[i][2] == '\0')
diff --git a/codemaker/source/cppumaker/cpputype.cxx b/codemaker/source/cppumaker/cpputype.cxx
index bb8e3ed7d33c..cb3422de16d0 100644
--- a/codemaker/source/cppumaker/cpputype.cxx
+++ b/codemaker/source/cppumaker/cpputype.cxx
@@ -53,6 +53,8 @@
namespace
{
+using FileType = codemaker::cppumaker::FileType;
+
bool isBootstrapType(OUString const & name)
{
static char const * const names[] = {
@@ -150,6 +152,17 @@ bool isBootstrapType(OUString const & name)
return std::any_of(std::begin(names), std::end(names), pred);
}
+OString getFileExtension(FileType eFileType)
+{
+ switch(eFileType)
+ {
+ default:
+ case FileType::HDL: return ".hdl";
+ case FileType::HPP: return ".hpp";
+ case FileType::EMBIND_CXX: return "_embind.cxx";
+ }
+}
+
class CppuType
{
public:
@@ -163,7 +176,7 @@ public:
void dump(CppuOptions const & options);
void dumpFile(
- std::u16string_view uri, std::u16string_view name, bool hpp,
+ std::u16string_view uri, std::u16string_view name, FileType eFileType,
CppuOptions const & options);
void dumpDependedTypes(
@@ -176,6 +189,8 @@ public:
virtual void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) = 0;
+ virtual void dumpEmbindCppFile(FileStream& o);
+
OUString dumpHeaderDefine(FileStream& o, std::u16string_view extension) const;
void dumpGetCppuType(FileStream & out);
@@ -226,6 +241,8 @@ protected:
assert(false); // this cannot happen
}
+ virtual void dumpEmbindDeclaration(FileStream &) {};
+
virtual void dumpFiles(OUString const & uri, CppuOptions const & options);
virtual void addLightGetCppuTypeIncludes(
@@ -305,8 +322,10 @@ const
void CppuType::dumpFiles(OUString const & uri, CppuOptions const & options)
{
- dumpFile(uri, name_, false, options);
- dumpFile(uri, name_, true, options);
+ dumpFile(uri, name_, FileType::HDL, options);
+ dumpFile(uri, name_, FileType::HPP, options);
+ if(options.isValid("-W"))
+ dumpFile(uri, name_, FileType::EMBIND_CXX, options);
}
void CppuType::addLightGetCppuTypeIncludes(
@@ -411,12 +430,12 @@ void CppuType::dump(CppuOptions const & options)
}
void CppuType::dumpFile(
- std::u16string_view uri, std::u16string_view name, bool hpp,
+ std::u16string_view uri, std::u16string_view name, FileType eFileType,
CppuOptions const & options)
{
OUString fileUri(
b2u(createFileNameFromType(
- u2b(uri), u2b(name), hpp ? ".hpp" : ".hdl")));
+ u2b(uri), u2b(name), getFileExtension(eFileType))));
if (fileUri.isEmpty()) {
throw CannotDumpException(OUString::Concat("empty target URI for entity ") + name);
}
@@ -430,13 +449,20 @@ void CppuType::dumpFile(
if(!out.isValid()) {
throw CannotDumpException("cannot open " + tmpUri + " for writing");
}
- codemaker::cppumaker::Includes includes(m_typeMgr, m_dependencies, hpp);
+ codemaker::cppumaker::Includes includes(m_typeMgr, m_dependencies, eFileType);
try {
- if (hpp) {
- addGetCppuTypeIncludes(includes);
- dumpHppFile(out, includes);
- } else {
- dumpHdlFile(out, includes);
+ switch(eFileType)
+ {
+ case FileType::HPP:
+ addGetCppuTypeIncludes(includes);
+ dumpHppFile(out, includes);
+ break;
+ case FileType::HDL:
+ dumpHdlFile(out, includes);
+ break;
+ case FileType::EMBIND_CXX:
+ dumpEmbindCppFile(out);
+ break;
}
} catch (...) {
out.close();
@@ -582,6 +608,16 @@ void CppuType::dumpHFileContent(
out << " *);\n\n#endif\n";
}
+void CppuType::dumpEmbindCppFile(FileStream &out)
+{
+ out << "#ifdef EMSCRIPTEN\n";
+ out << "#include <emscripten/bind.h>\n"
+ "#include <" << name_.replace('.', '/') << ".hpp>\n";
+ out << "using namespace emscripten;\n\n";
+ dumpEmbindDeclaration(out);
+ out << "#endif\n";
+}
+
void CppuType::dumpGetCppuType(FileStream & out)
{
if (name_ == "com.sun.star.uno.XInterface") {
@@ -1103,10 +1139,14 @@ public:
OUString const & name, rtl::Reference< TypeManager > const & typeMgr);
virtual void dumpDeclaration(FileStream& o) override;
+ virtual void dumpEmbindDeclaration(FileStream& o) override;
void dumpHppFile(FileStream& o, codemaker::cppumaker::Includes & includes) override;
void dumpAttributes(FileStream& o) const;
+ void dumpEmbindAttributeBindings(FileStream& o) const;
void dumpMethods(FileStream& o) const;
+ void dumpEmbindMethodBindings(FileStream& o, bool bDumpForReference=false) const;
+ void dumpEmbindWrapperFunc(FileStream& o, const unoidl::InterfaceTypeEntity::Method& method, bool bDumpForReference=false) const;
void dumpNormalGetCppuType(FileStream& o) override;
void dumpComprehensiveGetCppuType(FileStream& o) override;
void dumpCppuAttributeRefs(FileStream& o, sal_uInt32& index);
@@ -1168,15 +1208,65 @@ void InterfaceType::dumpDeclaration(FileStream & out)
<< ("static inline ::css::uno::Type const & SAL_CALL"
" static_type(void * = 0);\n\n");
dec();
+#ifdef EMSCRIPTEN
+ out << "#ifndef EMSCRIPTEN\n";
+#endif
out << "protected:\n";
inc();
out << indent() << "~" << id_
<< ("() SAL_NOEXCEPT {} // avoid warnings about virtual members and"
" non-virtual dtor\n");
+#ifdef EMSCRIPTEN
+ out << "#endif\n";
+#endif
dec();
out << "};\n\n";
}
+void InterfaceType::dumpEmbindDeclaration(FileStream & out)
+{
+ out << "namespace emscripten { namespace internal { \n"
+ "template<> void raw_destructor<" << codemaker::cpp::scopedCppName(u2b(name_))
+ << ">(" << codemaker::cpp::scopedCppName(u2b(name_)) << "*){}\n"
+ "}}\n";
+
+ out << "EMSCRIPTEN_BINDINGS(uno_bindings_";
+ codemaker::cppumaker::dumpTypeFullWithDecorator(out, name_, u"_");
+ codemaker::cppumaker::dumpTypeIdentifier(out, name_);
+ out << ") {\n";
+
+ out << "\nclass_<" << codemaker::cpp::scopedCppName(u2b(name_)) << ">(\"";
+ codemaker::cppumaker::dumpTypeFullWithDecorator(out, name_, u"$");
+ codemaker::cppumaker::dumpTypeIdentifier(out, name_);
+ out << "\")\n";
+
+ inc();
+ // dump bindings for attributes and methods.
+ dumpEmbindAttributeBindings(out);
+ dumpEmbindMethodBindings(out);
+ out << indent() << ";\n";
+ dec();
+
+ // dump reference bindings.
+ out << "\nclass_<::css::uno::Reference<" << codemaker::cpp::scopedCppName(u2b(name_)) << ">, base<::css::uno::BaseReference>>(\"";
+ codemaker::cppumaker::dumpTypeFullWithDecorator(out, name_, u"$");
+ codemaker::cppumaker::dumpTypeIdentifier(out, name_);
+ out << "Ref\")\n";
+ inc();
+ out << indent() << ".constructor<>()\n"
+ << indent() << ".constructor<::css::uno::BaseReference, ::css::uno::UnoReference_Query>()\n"
+ << indent() << ".function(\"is\", &::css::uno::Reference<" << codemaker::cpp::scopedCppName(u2b(name_)) << ">::is)\n"
+ << indent() << ".function(\"get\", &::css::uno::Reference<" << codemaker::cpp::scopedCppName(u2b(name_)) << ">::get, allow_raw_pointers())\n"
+ << indent() << ".function(\"set\", emscripten::select_overload<bool(const ::css::uno::Any&, com::sun::star::uno::UnoReference_Query)>(&::css::uno::Reference<" << codemaker::cpp::scopedCppName(u2b(name_)) << ">::set))\n";
+ dumpEmbindAttributeBindings(out);
+ dumpEmbindMethodBindings(out, true);
+ out << indent() << ";\n";
+ dec();
+
+ out << "}\n";
+}
+
+
void InterfaceType::dumpHppFile(
FileStream & out, codemaker::cppumaker::Includes & includes)
{
@@ -1228,6 +1318,31 @@ void InterfaceType::dumpAttributes(FileStream & out) const
}
}
+void InterfaceType::dumpEmbindAttributeBindings(FileStream& out) const
+{
+ if (!entity_->getDirectAttributes().empty())
+ {
+ out << indent() << "// Bindings for attributes\n";
+ }
+ for (const unoidl::InterfaceTypeEntity::Attribute& attr : entity_->getDirectAttributes())
+ {
+ if (m_isDeprecated || isDeprecated(attr.annotations))
+ continue;
+
+ out << indent();
+ out << ".function(\"";
+ out << "get" << attr.name << "\", &" << codemaker::cpp::scopedCppName(u2b(name_)) << "::get"
+ << attr.name << ")\n";
+ if (!attr.readOnly)
+ {
+ out << indent();
+ out << ".function(\"";
+ out << "set" << attr.name << "\", &" << codemaker::cpp::scopedCppName(u2b(name_))
+ << "::set" << attr.name << ")\n";
+ }
+ }
+}
+
void InterfaceType::dumpMethods(FileStream & out) const
{
if (!entity_->getDirectMethods().empty()) {
@@ -1268,6 +1383,115 @@ void InterfaceType::dumpMethods(FileStream & out) const
}
}
+void InterfaceType::dumpEmbindWrapperFunc(FileStream& out,
+ const unoidl::InterfaceTypeEntity::Method& method,
+ bool bDumpForReference) const
+{
+ out << indent();
+ out << ".function(\"" << method.name << "\", ";
+ out << indent() << "+[](";
+ if (bDumpForReference)
+ out << "::css::uno::Reference<";
+ out << codemaker::cpp::scopedCppName(u2b(name_));
+ if (bDumpForReference)
+ out << ">";
+ out << "* self";
+ if(!method.parameters.empty())
+ out << ",";
+
+ auto dumpParameters = [&](bool bDumpType)
+ {
+ // dumpParams with references as pointers
+ if (!method.parameters.empty())
+ {
+ out << " ";
+ for (std::vector<unoidl::InterfaceTypeEntity::Method::Parameter>::const_iterator
+ parameter(method.parameters.begin());
+ parameter != method.parameters.end();)
+ {
+ bool isConst;
+ bool isRef;
+ if (parameter->direction
+ == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN)
+ {
+ isConst = passByReference(parameter->type);
+ isRef = isConst;
+ }
+ else
+ {
+ isConst = false;
+ isRef = true;
+ }
+ // for the embind wrapper, we define a pointer instead of a reference.
+ if (bDumpType)
+ dumpType(out, parameter->type, isConst, /*isRef=*/false);
+ if (isRef)
+ out << "*";
+
+ out << " " << parameter->name;
+ ++parameter;
+ if (parameter != method.parameters.end())
+ {
+ out << ", ";
+ }
+ }
+ out << " ";
+ }
+ };
+ dumpParameters(/*bDumpType=*/true);
+
+ if (bDumpForReference)
+ {
+ out << ") { return self->get()->" << method.name << "(";
+ }
+ else
+ {
+ out << ") { return self->" << method.name << "(";
+ }
+
+ dumpParameters(/*bDumpType=*/false);
+ out << "); }, allow_raw_pointers() )\n";
+}
+
+void InterfaceType::dumpEmbindMethodBindings(FileStream & out, bool bDumpForReference) const
+{
+ if (!entity_->getDirectMethods().empty()) {
+ out << indent() << "// Bindings for methods\n";
+ }
+ for (const unoidl::InterfaceTypeEntity::Method& method : entity_->getDirectMethods()) {
+ if( m_isDeprecated || isDeprecated(method.annotations) )
+ continue;
+
+ // if dumping the method binding for a reference implementation
+ // dump wrapper.
+ if(bDumpForReference)
+ {
+ dumpEmbindWrapperFunc(out, method, true);
+ continue;
+ }
+
+ bool bHasOutParams = std::any_of(
+ method.parameters.begin(), method.parameters.end(),
+ [](const auto& parameter) {
+ return parameter.direction
+ != unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN;
+ });
+
+ if (bHasOutParams)
+ {
+ dumpEmbindWrapperFunc(out, method, false);
+ continue;
+ }
+
+ out << indent();
+ out << ".function(\"" << method.name << "\", &"
+ << codemaker::cpp::scopedCppName(u2b(name_))
+ << "::" << method.name << ")\n";
+ }
+}
+
+
+
void InterfaceType::dumpNormalGetCppuType(FileStream & out)
{
dumpGetCppuTypePreamble(out);
@@ -3515,7 +3739,9 @@ private:
}
virtual void dumpFiles(OUString const & uri, CppuOptions const & options) override {
- dumpFile(uri, name_, true, options);
+ dumpFile(uri, name_, FileType::HPP, options);
+ if(options.isValid("-W"))
+ dumpFile(uri, name_, FileType::EMBIND_CXX, options);
}
};
diff --git a/codemaker/source/cppumaker/cpputype.hxx b/codemaker/source/cppumaker/cpputype.hxx
index 40fc94f26c29..a6f8f9bfe8a3 100644
--- a/codemaker/source/cppumaker/cpputype.hxx
+++ b/codemaker/source/cppumaker/cpputype.hxx
@@ -28,6 +28,15 @@ namespace rtl { class OUString; }
class CppuOptions;
class TypeManager;
+namespace codemaker::cppumaker {
+enum class FileType
+{
+ HDL,
+ HPP,
+ EMBIND_CXX
+};
+}
+
void produce(
OUString const & name, rtl::Reference< TypeManager > const & manager,
codemaker::GeneratedTypeSet & generated, CppuOptions const & options);
diff --git a/codemaker/source/cppumaker/dumputils.cxx b/codemaker/source/cppumaker/dumputils.cxx
index 2a3e809e70f3..54867523b0d4 100644
--- a/codemaker/source/cppumaker/dumputils.cxx
+++ b/codemaker/source/cppumaker/dumputils.cxx
@@ -74,6 +74,20 @@ void dumpTypeIdentifier(FileStream & out, std::u16string_view entityName) {
out << entityName.substr(entityName.rfind('.') + 1);
}
+bool dumpTypeFullWithDecorator(FileStream& out, std::u16string_view entityName, std::u16string_view decorator)
+{
+ bool bOutput = false;
+ for (sal_Int32 i = 0; i >= 0;)
+ {
+ std::u16string_view id(o3tl::getToken(entityName, 0, '.', i));
+ if (i >= 0)
+ {
+ out << id << decorator;
+ bOutput = true;
+ }
+ }
+ return bOutput;
+}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/cppumaker/dumputils.hxx b/codemaker/source/cppumaker/dumputils.hxx
index 24e5bae3bede..c7021cba7408 100644
--- a/codemaker/source/cppumaker/dumputils.hxx
+++ b/codemaker/source/cppumaker/dumputils.hxx
@@ -35,6 +35,9 @@ bool dumpNamespaceOpen(FileStream& out, std::u16string_view entityName, bool ful
bool dumpNamespaceClose(FileStream& out, std::u16string_view entityName, bool fullModuleType);
void dumpTypeIdentifier(FileStream& out, std::u16string_view entityName);
+
+bool dumpTypeFullWithDecorator(FileStream& out, std::u16string_view entityName,
+ std::u16string_view decorator);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/codemaker/source/cppumaker/includes.cxx b/codemaker/source/cppumaker/includes.cxx
index 9dacdf268265..05f768bbc505 100644
--- a/codemaker/source/cppumaker/includes.cxx
+++ b/codemaker/source/cppumaker/includes.cxx
@@ -20,6 +20,7 @@
#include "includes.hxx"
+#include "cpputype.hxx"
#include "dependencies.hxx"
#include "dumputils.hxx"
@@ -40,8 +41,8 @@ using codemaker::cppumaker::Includes;
Includes::Includes(
rtl::Reference< TypeManager > manager,
- codemaker::cppumaker::Dependencies const & dependencies, bool hpp):
- m_manager(std::move(manager)), m_map(dependencies.getMap()), m_hpp(hpp),
+ codemaker::cppumaker::Dependencies const & dependencies, FileType eFileType):
+ m_manager(std::move(manager)), m_map(dependencies.getMap()), m_filetype(eFileType),
m_includeCassert(false),
m_includeAny(dependencies.hasAnyDependency()), m_includeReference(false),
m_includeSequence(dependencies.hasSequenceDependency()),
@@ -136,7 +137,7 @@ void dumpEmptyLineBeforeFirst(FileStream & out, bool * first) {
void Includes::dump(
FileStream & out, OUString const * companionHdl, bool exceptions)
{
- OSL_ASSERT(companionHdl == nullptr || m_hpp);
+ OSL_ASSERT(companionHdl == nullptr || m_filetype == FileType::HPP);
if (!m_includeReference) {
for (const auto& pair : m_map)
{
@@ -159,12 +160,12 @@ void Includes::dump(
{
if (exceptions || pair.second != Dependencies::KIND_EXCEPTION) {
dumpEmptyLineBeforeFirst(out, &first);
- if (m_hpp || pair.second == Dependencies::KIND_BASE
+ if ((m_filetype == FileType::HPP) || pair.second == Dependencies::KIND_BASE
|| !isInterfaceType(u2b(pair.first)))
{
// If we know our name, then avoid including ourselves.
if (!companionHdl || *companionHdl != pair.first) {
- dumpInclude(out, u2b(pair.first), m_hpp);
+ dumpInclude(out, u2b(pair.first), (m_filetype == FileType::HPP));
}
} else {
bool ns = dumpNamespaceOpen(out, pair.first, false);
@@ -185,22 +186,22 @@ void Includes::dump(
static char const * hxxExtension[2] = { "h", "hxx" };
if (m_includeAny) {
dumpEmptyLineBeforeFirst(out, &first);
- out << "#include \"com/sun/star/uno/Any." << hxxExtension[m_hpp]
+ out << "#include \"com/sun/star/uno/Any." << hxxExtension[(m_filetype == FileType::HPP)]
<< "\"\n";
}
if (m_includeReference) {
dumpEmptyLineBeforeFirst(out, &first);
- out << "#include \"com/sun/star/uno/Reference." << hxxExtension[m_hpp]
+ out << "#include \"com/sun/star/uno/Reference." << hxxExtension[(m_filetype == FileType::HPP)]
<< "\"\n";
}
if (m_includeSequence) {
dumpEmptyLineBeforeFirst(out, &first);
- out << "#include \"com/sun/star/uno/Sequence." << hxxExtension[m_hpp]
+ out << "#include \"com/sun/star/uno/Sequence." << hxxExtension[(m_filetype == FileType::HPP)]
<< "\"\n";
}
if (m_includeType) {
dumpEmptyLineBeforeFirst(out, &first);
- out << "#include \"com/sun/star/uno/Type." << hxxExtension[m_hpp]
+ out << "#include \"com/sun/star/uno/Type." << hxxExtension[(m_filetype == FileType::HPP)]
<< "\"\n";
}
if (m_includeCppuMacrosHxx) {
diff --git a/codemaker/source/cppumaker/includes.hxx b/codemaker/source/cppumaker/includes.hxx
index 8cd830b4a731..dcdcb5836f7e 100644
--- a/codemaker/source/cppumaker/includes.hxx
+++ b/codemaker/source/cppumaker/includes.hxx
@@ -29,12 +29,13 @@ class FileStream;
class TypeManager;
namespace codemaker::cppumaker {
+enum class FileType;
class Includes {
public:
Includes(
rtl::Reference< TypeManager > manager,
- Dependencies const & dependencies, bool hpp);
+ Dependencies const & dependencies, FileType eFileType);
~Includes();
@@ -73,7 +74,7 @@ private:
rtl::Reference< TypeManager > m_manager;
Dependencies::Map m_map;
- bool m_hpp;
+ FileType m_filetype;
bool m_includeCassert;
bool m_includeAny;
bool m_includeReference;
diff --git a/desktop/Executable_soffice_bin.mk b/desktop/Executable_soffice_bin.mk
index ce908c1be318..c2d811c2e86c 100644
--- a/desktop/Executable_soffice_bin.mk
+++ b/desktop/Executable_soffice_bin.mk
@@ -48,9 +48,12 @@ endif
endif
ifeq ($(OS),EMSCRIPTEN)
+$(call gb_LinkTarget_get_target,$(call gb_Executable_get_linktarget,soffice_bin)) : $(call gb_StaticLibrary_get_linktarget_target,unoembind)
+$(call gb_LinkTarget_get_headers_target,$(call gb_Executable_get_linktarget,soffice_bin)) : $(call gb_StaticLibrary_get_headers_target,unoembind)
+$(call gb_LinkTarget__static_lib_dummy_depend,unoembind)
$(eval $(call gb_Executable_add_ldflags,soffice_bin,\
- -s EXPORTED_FUNCTIONS=["_main"$(COMMA)"_libreofficekit_hook"$(COMMA)"_libreofficekit_hook_2"$(COMMA)"_lok_preinit"$(COMMA)"_lok_preinit_2"] \
+ -s EXPORTED_FUNCTIONS=["_main"$(COMMA)"_libreofficekit_hook"$(COMMA)"_libreofficekit_hook_2"$(COMMA)"_lok_preinit"$(COMMA)"_lok_preinit_2"] -Wl$(COMMA)--whole-archive $(call gb_StaticLibrary_get_target,unoembind) -Wl$(COMMA)--no-whole-archive \
))
endif
diff --git a/solenv/gbuild/UnoApi.mk b/solenv/gbuild/UnoApi.mk
index f396642901fe..9ed314703f33 100644
--- a/solenv/gbuild/UnoApi.mk
+++ b/solenv/gbuild/UnoApi.mk
@@ -36,6 +36,8 @@ define gb_UnoApi_add_idlfiles
$(call gb_UnoApiTarget_add_idlfiles,$(1),$(2),$(3))
$(call gb_UnoApiHeadersTarget_add_headerfiles,$(1),$(2),$(addsuffix .hpp,$(3)))
$(call gb_UnoApiHeadersTarget_add_headerfiles,$(1),$(2),$(addsuffix .hdl,$(3)))
+$(if $(filter EMSCRIPTEN, $(OS)),\
+ $(call gb_UnoApiHeadersTarget_add_embind,$(1),$(2),$(addsuffix _embind,$(3))))
endef
@@ -69,4 +71,19 @@ $(call gb_UnoApiTarget_set_reference_rdbfile,$(1),$(2))
endef
+ifeq ($(OS),EMSCRIPTEN)
+$(eval $(call gb_StaticLibrary_StaticLibrary,unoembind))
+$(eval $(call gb_StaticLibrary_set_include,unoembind,\
+ $$(INCLUDE) \
+))
+$(eval $(call gb_StaticLibrary_use_api,unoembind,\
+ offapi \
+ udkapi \
+))
+$(eval $(call gb_StaticLibrary_add_exception_objects,unoembind,\
+ static/source/unoembindhelpers/PrimaryBindings\
+))
+
+endif
+
# vim: set noet sw=4 ts=4:
diff --git a/solenv/gbuild/UnoApiTarget.mk b/solenv/gbuild/UnoApiTarget.mk
index 67e8bccca906..7c52ecc81f1e 100644
--- a/solenv/gbuild/UnoApiTarget.mk
+++ b/solenv/gbuild/UnoApiTarget.mk
@@ -151,7 +151,8 @@ $(call gb_UnoApiHeadersTarget_get_real_comprehensive_target,%) : \
$(gb_UnoApiHeadersTarget_CPPUMAKERDEPS)
$(call gb_Output_announce,$*,$(true),HPC,3)
$(call gb_Trace_StartRange,$*,HPC)
- $(call gb_UnoApiHeadersTarget__command,$@,$*,$(call gb_UnoApiHeadersTarget_get_comprehensive_dir,$*),-C)
+ $(call gb_UnoApiHeadersTarget__command,$@,$*,$(call gb_UnoApiHeadersTarget_get_comprehensive_dir,$*), \
+ -C $(if $(filter EMSCRIPTEN, $(OS)), -W))
$(call gb_Trace_EndRange,$*,HPC)
$(call gb_UnoApiHeadersTarget_get_real_target,%) : \
@@ -231,6 +232,21 @@ define gb_UnoApiHeadersTarget_add_headerfiles
$(foreach hdr,$(3),$(call gb_UnoApiHeadersTarget_add_headerfile,$(1),$(2)/$(hdr)))
endef
+# call gb_UnoApiEmbindTarget_add_embind,unoapi,directory,headerfilenames
+define gb_UnoApiHeadersTarget_add_embind
+$(if $(filter offapi udkapi, $(1)),\
+ $(foreach hdr,$(3),$(eval $(call gb_UnoApiEmbindTarget__add_embind,$(1),$(2),$(hdr)))))
+endef
+
+# CaptionEscapeDirection contains "auto" as a variable name.. so exclude that
+define gb_UnoApiEmbindTarget__add_embind
+$(if $(filter-out CaptionEscapeDirection_embind, $(3)),\
+$(eval $(call gb_StaticLibrary_add_generated_exception_objects,unoembind,\
+ UnoApiHeadersTarget/$(1)/comprehensive/$(2)/$(3) \
+)))
+
+endef
+
define gb_UnoApiHeadersTarget__use_api_for_target
$(call gb_UnoApiHeadersTarget_get_$(3),$(1)) : $(call gb_UnoApiTarget_get_target,$(2))
$(call gb_UnoApiHeadersTarget_get_$(3),$(1)) : UNOAPI_DEPS += -X$(call gb_UnoApiTarget_get_target,$(2))
diff --git a/solenv/gbuild/platform/unxgcc.mk b/solenv/gbuild/platform/unxgcc.mk
index bfb860a41fc2..29adbf9dc42f 100644
--- a/solenv/gbuild/platform/unxgcc.mk
+++ b/solenv/gbuild/platform/unxgcc.mk
@@ -191,8 +191,18 @@ endef
define gb_LinkTarget__command_staticlink
$(call gb_Helper_abbreviate_dirs,\
rm -f $(1) && \
- $(if $(filter EMSCRIPTEN,$(OS)),unset PYTHONWARNINGS ;) \
+ $(if $(filter EMSCRIPTEN,$(OS)),unset PYTHONWARNINGS ; \
+ RESPONSEFILE=$(call gb_var2file,$(shell $(gb_MKTEMP)), \
+ $(foreach object,$(COBJECTS),$(call gb_CObject_get_target,$(object))) \
+ $(foreach object,$(CXXOBJECTS),$(call gb_CxxObject_get_target,$(object))) \
+ $(foreach object,$(ASMOBJECTS),$(call gb_AsmObject_get_target,$(object))) \
+ $(foreach object,$(GENCOBJECTS),$(call gb_GenCObject_get_target,$(object))) \
+ $(foreach object,$(GENCXXOBJECTS),$(call gb_GenCxxObject_get_target,$(object))) \
+ $(foreach object,$(GENNASMOBJECTS),$(call gb_GenNasmObject_get_target,$(object))) \
+ $(foreach extraobjectlist,$(EXTRAOBJECTLISTS),$(shell cat $(extraobjectlist)))) && ) \
$(gb_AR) $(gb_LTOPLUGINFLAGS) -rsu $(1) \
+ $(if $(filter EMSCRIPTEN, $(OS)), \
+ @$${RESPONSEFILE} $(if $(findstring s,$(MAKEFLAGS)),2> /dev/null); rm $${RESPONSEFILE},\
$(foreach object,$(COBJECTS),$(call gb_CObject_get_target,$(object))) \
$(foreach object,$(CXXOBJECTS),$(call gb_CxxObject_get_target,$(object))) \
$(foreach object,$(ASMOBJECTS),$(call gb_AsmObject_get_target,$(object))) \
@@ -200,7 +210,7 @@ $(call gb_Helper_abbreviate_dirs,\
$(foreach object,$(GENCXXOBJECTS),$(call gb_GenCxxObject_get_target,$(object))) \
$(foreach object,$(GENNASMOBJECTS),$(call gb_GenNasmObject_get_target,$(object))) \
$(foreach extraobjectlist,$(EXTRAOBJECTLISTS),@$(extraobjectlist)) \
- $(if $(findstring s,$(MAKEFLAGS)),2> /dev/null))
+ $(if $(findstring s,$(MAKEFLAGS)),2> /dev/null)))
endef
define gb_LinkTarget__command
diff --git a/static/README.wasm.md b/static/README.wasm.md
index 6e74599eb3ae..f39a79247d00 100644
--- a/static/README.wasm.md
+++ b/static/README.wasm.md
@@ -214,6 +214,45 @@ WASM dynamic dispatch:
- <https://fitzgeraldnick.com/2018/04/26/how-does-dynamic-dispatch-work-in-wasm.html>
+### UNO bindings with Embind
+
+Right now there's a very rough implementation in place. With lots of different
+bits unimplemented. And it _might_ be leaking memory. i.e. Lots of room for
+improvement! ;)
+
+Some usage examples through javascript of the current implementation:
+```js
+// inserts a string at the start of the Writer document.
+xModel = Module.getCurrentModelFromViewSh();
+xTextDocument = new Module.com$sun$star$text$XTextDocumentRef(xModel, Module.UnoReference_Query.UNO_QUERY);
+xText = xTextDocument.getText();
+xSimpleText = new Module.com$sun$star$text$XSimpleTextRef(xText, Module.UnoReference_Query.UNO_QUERY);
+xTextCursor = xSimpleText.createTextCursor();
+xTextRange = new Module.com$sun$star$text$XTextRangeRef(xTextCursor, Module.UnoReference_Query.UNO_QUERY);
+xTextRange.setString(new Module.OUString("string here!"));
+xModel.delete(); xTextDocument.delete(); xText.delete(); xSimpleText.delete(); xTextCursor.delete(); xTextRange.delete();
+```
+
+```js
+// changes each paragraph of the Writer document to a random color.
+xModel = Module.getCurrentModelFromViewSh();
+xTextDocument = new Module.com$sun$star$text$XTextDocumentRef(xModel, Module.UnoReference_Query.UNO_QUERY);
+xText = xTextDocument.getText();
+xEnumAccess = new Module.com$sun$star$container$XEnumerationAccessRef(xText, Module.UnoReference_Query.UNO_QUERY);
+xParaEnumeration = xEnumAccess.createEnumeration();
+
+while (xParaEnumeration.hasMoreElements()) {
+ xParagraph = new Module.com$sun$star$text$XTextRangeRef();
+ xParagraph.set(xParaEnumeration.nextElement(), Module.UnoReference_Query.UNO_QUERY);
+ if (xParagraph.is()) {
+ xParaProps = new Module.com$sun$star$beans$XPropertySetRef(xParagraph, Module.UnoReference_Query.UNO_QUERY);
+ xParaProps.setPropertyValue(new Module.OUString("CharColor"), new Module.Any(Math.floor(Math.random() * 0xFFFFFF), Module.UnoType.long));
+ }
+}
+```
+
+
+
## Tools for problem diagnosis
* `nm -s` should list the symbols in the archive, based on the index generated by ranlib.
diff --git a/static/source/unoembindhelpers/PrimaryBindings.cxx b/static/source/unoembindhelpers/PrimaryBindings.cxx
new file mode 100644
index 000000000000..e9a0c496310b
--- /dev/null
+++ b/static/source/unoembindhelpers/PrimaryBindings.cxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; 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/.
+ */
+#ifdef EMSCRIPTEN
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/uno/XReference.hpp>
+
+#include <emscripten/bind.h>
+
+#include <sal/log.hxx>
+#include <sfx2/viewsh.hxx>
+
+using namespace emscripten;
+using namespace css::uno;
+
+namespace
+{
+Reference<css::frame::XModel> getCurrentModelFromViewSh()
+{
+ SfxViewShell* pSh = nullptr;
+ pSh = SfxViewShell::Current();
+ if (!pSh)
+ {
+ return {};
+ }
+ return pSh->GetCurrentDocument();
+}
+}
+
+EMSCRIPTEN_BINDINGS(PrimaryBindings)
+{
+ // Reference bits
+ class_<BaseReference>("BaseReference");
+ enum_<UnoReference_Query>("UnoReference_Query").value("UNO_QUERY", UNO_QUERY);
+
+ class_<OUString>("OUString")
+ .constructor(
+ +[](const std::string& rString) -> OUString {
+ return OUString::fromUtf8(std::string_view{ rString.c_str() });
+ },
+ allow_raw_pointers())
+ .function("toString", +[](const OUString& rSelf) -> std::string {
+ return std::string{ rSelf.toUtf8() };
+ });
+
+ // Types used for Any construction
+ enum_<TypeClass>("UnoType")
+ .value("void", TypeClass::TypeClass_VOID)
+ .value("char", TypeClass::TypeClass_CHAR)
+ .value("bool", TypeClass::TypeClass_BOOLEAN)
+ .value("byte", TypeClass::TypeClass_BYTE)
+ .value("short", TypeClass::TypeClass_SHORT)
+ .value("unsigned_short", TypeClass::TypeClass_UNSIGNED_SHORT)
+ .value("long", TypeClass::TypeClass_LONG)
+ .value("unsigned_long", TypeClass::TypeClass_UNSIGNED_LONG)
+ .value("hyper", TypeClass::TypeClass_HYPER)
+ .value("unsigned_hyper", TypeClass::TypeClass_UNSIGNED_HYPER)
+ .value("float", TypeClass::TypeClass_FLOAT)
+ .value("double", TypeClass::TypeClass_DOUBLE)
+ .value("string", TypeClass::TypeClass_STRING);
+
+ // Any
+ class_<Any>("Any").constructor(
+ +[](const val& rObject, const TypeClass& rUnoType) -> Any {
+ switch (rUnoType)
+ {
+ case TypeClass_VOID:
+ break;
+ case TypeClass_CHAR:
+ return Any{ rObject.as<sal_Int8>() };
+ case TypeClass_BOOLEAN:
+ return Any{ rObject.as<bool>() };
+ case TypeClass_BYTE:
+ return Any{ rObject.as<sal_Int8>() };
+ case TypeClass_SHORT:
+ return Any{ rObject.as<sal_Int16>() };
+ case TypeClass_UNSIGNED_SHORT:
+ return Any{ rObject.as<sal_uInt16>() };
+ case TypeClass_LONG:
+ return Any{ rObject.as<sal_Int32>() };
+ case TypeClass_UNSIGNED_LONG:
+ return Any{ rObject.as<sal_uInt32>() };
+ case TypeClass_HYPER:
+ return Any{ rObject.as<sal_Int64>() };
+ case TypeClass_UNSIGNED_HYPER:
+ return Any{ rObject.as<sal_uInt64>() };
+ case TypeClass_FLOAT:
+ return Any{ rObject.as<float>() };
+ case TypeClass_DOUBLE:
+ return Any{ rObject.as<double>() };
+ case TypeClass_STRING:
+ return Any{ OUString::fromUtf8(std::string_view{ rObject.as<std::string>() }) };
+ case TypeClass_TYPE:
+ case TypeClass_ANY:
+ case TypeClass_ENUM:
+ case TypeClass_STRUCT:
+ case TypeClass_EXCEPTION:
+ case TypeClass_SEQUENCE:
+ case TypeClass_INTERFACE:
+ case TypeClass_TYPEDEF:
+ case TypeClass_SERVICE:
+ case TypeClass_MODULE:
+ case TypeClass_INTERFACE_METHOD:
+ case TypeClass_INTERFACE_ATTRIBUTE:
+ default:
+ break;
+ }
+ return {};
+ },
+ allow_raw_pointers());
+
+ function("getCurrentModelFromViewSh", &getCurrentModelFromViewSh);
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */