From 86103f3af562152f642140e393c7beacac311dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20S=C3=B8rvig?= Date: Tue, 10 May 2022 09:36:59 +0200 Subject: [PATCH] wasm: don't enable specialHTMLTargets by default Adding specialHTMLTargets to EXPORTED_RUNTIME_METHODS carries the obligation to actually use it as well; failing to do so makes Emscripten stop with a reference error on startup. However, we can't guarantee that Qt will use it in all cases. The current usage depends on QGuiApplication being used. Application code could be using QCoreApplication, or no application object at all. Detect if specialHTMLTargets is present instead, and then enable the code paths which uses it if that's the case. This means that apps which want to use e.g. multiple browser windows can opt into support by making sure EXPORTED_RUNTIME_METHODS contains specialHTMLTargets. Change-Id: I81105aa01946602fcf593f170e305d7dc9bad3be Reviewed-by: Lorn Potter --- cmake/QtWasmHelpers.cmake | 2 +- mkspecs/wasm-emscripten/qmake.conf | 2 +- src/corelib/kernel/qeventdispatcher_wasm.cpp | 1 + src/plugins/platforms/wasm/qwasmscreen.cpp | 47 +++++++++++++++----- src/plugins/platforms/wasm/qwasmscreen.h | 3 ++ 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/cmake/QtWasmHelpers.cmake b/cmake/QtWasmHelpers.cmake index 5e09feac29..7cdd822606 100644 --- a/cmake/QtWasmHelpers.cmake +++ b/cmake/QtWasmHelpers.cmake @@ -4,7 +4,7 @@ function (qt_internal_setup_wasm_target_properties wasmTarget) target_link_options("${wasmTarget}" INTERFACE "SHELL:-s ERROR_ON_UNDEFINED_SYMBOLS=1" - "SHELL:-s EXPORTED_RUNTIME_METHODS=[UTF16ToString,stringToUTF16,specialHTMLTargets]" + "SHELL:-s EXPORTED_RUNTIME_METHODS=[UTF16ToString,stringToUTF16]" "SHELL:-s USE_WEBGL2=1" "--bind" "SHELL:-s FETCH=1" diff --git a/mkspecs/wasm-emscripten/qmake.conf b/mkspecs/wasm-emscripten/qmake.conf index 140f2b4801..b95cf0fcc6 100644 --- a/mkspecs/wasm-emscripten/qmake.conf +++ b/mkspecs/wasm-emscripten/qmake.conf @@ -34,7 +34,7 @@ EMCC_COMMON_LFLAGS += \ -s FULL_ES3=1 \ -s USE_WEBGL2=1 \ -s ERROR_ON_UNDEFINED_SYMBOLS=1 \ - -s EXPORTED_RUNTIME_METHODS=[UTF16ToString,stringToUTF16,specialHTMLTargets] \ + -s EXPORTED_RUNTIME_METHODS=[UTF16ToString,stringToUTF16] \ --bind \ -s FETCH=1 \ -s MODULARIZE=1 \ diff --git a/src/corelib/kernel/qeventdispatcher_wasm.cpp b/src/corelib/kernel/qeventdispatcher_wasm.cpp index d2b01905fe..543811ae1b 100644 --- a/src/corelib/kernel/qeventdispatcher_wasm.cpp +++ b/src/corelib/kernel/qeventdispatcher_wasm.cpp @@ -11,6 +11,7 @@ #include "emscripten.h" #include #include +#include QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp index 51593b9d29..f2d600dcb0 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.cpp +++ b/src/plugins/platforms/wasm/qwasmscreen.cpp @@ -78,9 +78,14 @@ QWasmScreen::QWasmScreen(const emscripten::val &containerOrCanvas) // apps/ages only, since Emscripten uses the main document to look up the element. // As a workaround for this, Emscripten supports registering custom mappings in the // "specialHTMLTargets" object. Add a mapping for the canvas for this screen. - emscripten::val specialHtmlTargets = emscripten::val::module_property("specialHTMLTargets"); - std::string id = std::string("!qtcanvas_") + std::to_string(uint32_t(this)); - specialHtmlTargets.set(id, m_canvas); + // + // This functionality is gated on "specialHTMLTargets" being available as a module + // property. One way to ensure this is the case is to add it to EXPORTED_RUNTIME_METHODS. + // Qt does not currently do this by default since if added it _must_ be used in order + // to avoid an undefined reference error at startup, and there are cases when Qt won't use + // it, for example if QGuiApplication is not usded. + if (hasSpecialHtmlTargets()) + emscripten::val::module_property("specialHTMLTargets").set(canvasSpecialHtmlTargetId(), m_canvas); // Install event handlers on the container/canvas. This must be // done after the canvas has been created above. @@ -97,9 +102,9 @@ QWasmScreen::~QWasmScreen() // event handlers. m_compositor = nullptr; - emscripten::val specialHtmlTargets = emscripten::val::module_property("specialHTMLTargets"); - std::string id = std::string("!qtcanvas_") + std::to_string(uint32_t(this)); - specialHtmlTargets.set(id, emscripten::val::undefined()); + if (hasSpecialHtmlTargets()) + emscripten::val::module_property("specialHTMLTargets") + .set(canvasSpecialHtmlTargetId(), emscripten::val::undefined()); m_canvas.set(m_canvasResizeObserverCallbackContextPropertyName, emscripten::val(intptr_t(0))); } @@ -146,13 +151,33 @@ QString QWasmScreen::canvasId() const return QWasmString::toQString(m_canvas["id"]); } -// Returns the canvas _target_ id, for use with Emscripten's -// event registration functions. The target id is a globally -// unique id, unlike the html element id which is only unique -// within one html document. See specialHtmlTargets. +// Returns the canvas _target_ id, for use with Emscripten's event registration +// functions. This either based on the id registered in specialHtmlTargets, or +// on the canvas id. QString QWasmScreen::canvasTargetId() const { - return QStringLiteral("!qtcanvas_") + QString::number(int32_t(this)); + if (hasSpecialHtmlTargets()) + return QString::fromStdString(canvasSpecialHtmlTargetId()); + else + return QStringLiteral("#") + canvasId(); +} + +std::string QWasmScreen::canvasSpecialHtmlTargetId() const +{ + // Return a globally unique id for the canvas. We can choose any string, + // as long as it starts with a "!". + return std::string("!qtcanvas_") + std::to_string(uint32_t(this)); +} + +bool QWasmScreen::hasSpecialHtmlTargets() const +{ + static bool gotIt = []{ + // specialHTMLTargets is a JavaScript Array if available. Note that it is + // an abort() function if not, so a simple isUndefined() test wont't work here. + return emscripten::val::module_property("specialHTMLTargets") + ["constructor"]["name"].as() == std::string("Array"); + }(); + return gotIt; } QRect QWasmScreen::geometry() const diff --git a/src/plugins/platforms/wasm/qwasmscreen.h b/src/plugins/platforms/wasm/qwasmscreen.h index 9887e8abab..0e7d5f1e43 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.h +++ b/src/plugins/platforms/wasm/qwasmscreen.h @@ -62,6 +62,9 @@ public slots: void setGeometry(const QRect &rect); private: + std::string canvasSpecialHtmlTargetId() const; + bool hasSpecialHtmlTargets() const; + emscripten::val m_container; emscripten::val m_canvas; std::unique_ptr m_compositor;