summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephan Bergmann <stephan.bergmann@allotropia.de>2024-08-14 16:54:49 +0200
committerStephan Bergmann <stephan.bergmann@allotropia.de>2024-08-14 21:57:00 +0200
commitcccc983eb3f0532dbf7e3edf4477ce63ec3d2795 (patch)
treecba9fe3b1bd9277fba60173199ffb43cdaf5a365
parentd193bf5cec65ab55d5a76b3a4f68eb52e5a747f3 (diff)
Emscripten: Run external code on LO's main thread
...and not the browser's main thread. Those are different threads now since 6e6451ce96f47e0ef5e8ecf1750f394ff3fb48e4 "Emscripten: Move the Qt event loop off the JS main thread". Running `Module.uno_init.then` on the browser's main thread would never trigger, as that promise is only resolved on LO's main thread. When external code was included in soffice.js via EMSCRIPTEN_EXTRA_SOFFICE_POST_JS, that didn't make a difference: Emscripten effectively replicates that code to all the worker threads, so whatever worker thread resolved the Module.uno_init promise (i.e., the LO main thread) had the external code available and ran it. But when external code was included directly in some HTML file (which "manually" provides a canvas and loads soffice.js, not relying on the qt_soffice.html convenience functionality), it was available in the browser's main thread but not in LO's main thread. For that use case, introduce a new Module.uno_scripts array that can be set up in the HTML file to contain an array of URLs (represented as strings) of scripts to load into LO's main thread. (Alternatively, running external code on the browser's main thread rather than on LO's main thread could be more ideal in the sense that the external code would then have access to the browser's document object. But, for one, it would be less ideal in the sense that we would then potentially again execute LO code (which we call into from the external code via UNO) on the browser's main thread, which would bring back the issues that 6e6451ce96f47e0ef5e8ecf1750f394ff3fb48e4 "Emscripten: Move the Qt event loop off the JS main thread" solved. And, for another, when I experimentally tried it out, it caused massive Qt threading issues, so I quickly gave up again.) Change-Id: If01a7859751706f168e93ccac75758ae5ce17cd2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171870 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
-rw-r--r--desktop/source/app/appinit.cxx51
-rw-r--r--static/README.wasm.md14
2 files changed, 62 insertions, 3 deletions
diff --git a/desktop/source/app/appinit.cxx b/desktop/source/app/appinit.cxx
index f2b7edba1c8e..6f8bffa1146a 100644
--- a/desktop/source/app/appinit.cxx
+++ b/desktop/source/app/appinit.cxx
@@ -19,6 +19,10 @@
#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <string>
+#include <vector>
#include <app.hxx>
#include <dp_shared.hxx>
@@ -46,6 +50,8 @@
#if defined EMSCRIPTEN
#include <emscripten.h>
+#include <emscripten/threading.h>
+#include <emscripten/val.h>
#include <bindings_uno.hxx>
#endif
@@ -53,6 +59,48 @@ using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::ucb;
+#if defined EMSCRIPTEN
+
+namespace {
+
+extern "C" void getUnoScriptUrls(std::vector<std::u16string> * urls) {
+ assert(urls != nullptr);
+ auto const val = emscripten::val::module_property("uno_scripts");
+ if (!val.isUndefined()) {
+ auto const len = val["length"].as<std::uint32_t>();
+ for (std::uint32_t i = 0; i != len; ++i) {
+ urls->push_back(val[i].as<std::u16string>());
+ }
+ }
+}
+
+EM_JS(void, runUnoScriptUrl, (char16_t const * url), {
+ fetch(UTF16ToString(url)).then(res => {
+ if (!res.ok) {
+ throw Error(
+ "Loading <" + res.url + "> failed with " + res.status + " " + res.statusText);
+ }
+ return res.blob();
+ }).then(blob => blob.text()).then(text => eval(text));
+});
+
+void initUno() {
+ init_unoembind_uno();
+ EM_ASM(Module.uno_init$resolve(););
+ std::vector<std::u16string> urls;
+ emscripten_sync_run_in_main_runtime_thread(EM_FUNC_SIG_VI, getUnoScriptUrls, &urls);
+ for (auto const & url: urls) {
+ if (url.find('\0') != std::u16string::npos) {
+ throw std::invalid_argument("Module.uno_scripts element contains embedded NUL");
+ }
+ runUnoScriptUrl(url.c_str());
+ }
+}
+
+}
+
+#endif
+
namespace desktop
{
@@ -86,8 +134,7 @@ void Desktop::InitApplicationServiceManager()
#endif
comphelper::setProcessServiceFactory(sm);
#if defined EMSCRIPTEN
- init_unoembind_uno();
- EM_ASM(Module.uno_init$resolve(););
+ initUno();
#endif
}
diff --git a/static/README.wasm.md b/static/README.wasm.md
index 84635d09390d..c69129303aa5 100644
--- a/static/README.wasm.md
+++ b/static/README.wasm.md
@@ -241,7 +241,19 @@ Module.uno_init.then(function() {
});
```
-
+If you enter the above examples into the browser console, you need to enter them into the console of
+the first soffice.worker.js thread, which is the LO main thread since we use -sPROXY_TO_PTHREAD, not
+into the console of the browser's main thread.
+
+Alternatively, you can do the following: Put an example into some file like `example.js` that you
+put next to the `qt_soffice.html` that you serve to the browser (i.e., in
+`workdir/installation/LibreOffice/emscripten/`). Create another small JS snippet file like
+`include.js` (which is only needed during the build) containing
+```
+Module.uno_scripts = ['./example.js'];
+```
+And rebuild LO configured with an additional
+`EMSCRIPTEN_EXTRA_SOFFICE_POST_JS=/...path-to.../include.js`.
## Tools for problem diagnosis