desktop/source/app/appinit.cxx |   51 +++++++++++++++++++++++++++++++++++++++--
 static/README.wasm.md          |   14 ++++++++++-
 2 files changed, 62 insertions(+), 3 deletions(-)

New commits:
commit cccc983eb3f0532dbf7e3edf4477ce63ec3d2795
Author:     Stephan Bergmann <[email protected]>
AuthorDate: Wed Aug 14 16:54:49 2024 +0200
Commit:     Stephan Bergmann <[email protected]>
CommitDate: Wed Aug 14 21:57:00 2024 +0200

    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 <[email protected]>

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('
+            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
 

Reply via email to