summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMorten Johan Sørvig <[email protected]>2021-11-27 23:56:40 +0100
committerMorten Johan Sørvig <[email protected]>2022-04-05 22:34:44 +0200
commit08733dff582e220ba381939e74c623a5321fb9a5 (patch)
tree11c8f3212489b555eea37ecd881724ed0f18ceb1
parent4bc85b9850303fa20206f8774af88d72593d3454 (diff)
wasm: use “specialHtmlTargets” for canvas lookup
We’d like to support use cases which require using multiple html documents, for example when displaying application content using more than one browser window. Normally Emscripten uses the primary html document when looking up elements by id, which means that targeting elements on secondary documents is not possible. Emscripten does provide a workaround: the application can create custom id mappings to any html element on the “specialHtmlTargets” object, and then use the “!id” syntax instead of normal “#id” lookup. Change-Id: I4dda920868cfbc6f8991425daf8933144c0ffad8 Reviewed-by: Morten Johan Sørvig <[email protected]>
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.cpp4
-rw-r--r--src/plugins/platforms/wasm/qwasmopenglcontext.cpp7
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.cpp29
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.h1
4 files changed, 33 insertions, 8 deletions
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp
index 5c5fc80adba..bfcb1a9fe58 100644
--- a/src/plugins/platforms/wasm/qwasmcompositor.cpp
+++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp
@@ -115,7 +115,7 @@ QWasmCompositor::~QWasmCompositor()
void QWasmCompositor::deregisterEventHandlers()
{
- QByteArray canvasSelector = "#" + screen()->canvasId().toUtf8();
+ QByteArray canvasSelector = screen()->canvasTargetId().toUtf8();
emscripten_set_keydown_callback(canvasSelector.constData(), 0, 0, NULL);
emscripten_set_keyup_callback(canvasSelector.constData(), 0, 0, NULL);
@@ -156,7 +156,7 @@ void QWasmCompositor::destroy()
void QWasmCompositor::initEventHandlers()
{
- QByteArray canvasSelector = "#" + screen()->canvasId().toUtf8();
+ QByteArray canvasSelector = screen()->canvasTargetId().toUtf8();
eventTranslator->g_usePlatformMacSpecifics
= (QWasmIntegration::get()->platform == QWasmIntegration::MacOSPlatform);
diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
index c122335a575..4462e55524a 100644
--- a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
+++ b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
@@ -87,13 +87,12 @@ bool QWasmOpenGLContext::maybeCreateEmscriptenContext(QPlatformSurface *surface)
if (m_context)
return m_screen == screen;
- QString canvasId = QWasmScreen::get(screen)->canvasId();
- m_context = createEmscriptenContext(canvasId, m_requestedFormat);
+ m_context = createEmscriptenContext(QWasmScreen::get(screen)->canvasTargetId(), m_requestedFormat);
m_screen = screen;
return true;
}
-EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(const QString &canvasId, QSurfaceFormat format)
+EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(const QString &canvasTargetId, QSurfaceFormat format)
{
EmscriptenWebGLContextAttributes attributes;
emscripten_webgl_init_context_attributes(&attributes); // Populate with default attributes
@@ -114,7 +113,7 @@ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(cons
attributes.depth = useDepthStencil;
attributes.stencil = useDepthStencil;
- QByteArray convasSelector = "#" + canvasId.toUtf8();
+ QByteArray convasSelector = canvasTargetId.toUtf8();
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(convasSelector.constData(), &attributes);
return context;
diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp
index 52da924f8ff..c32adbe13fd 100644
--- a/src/plugins/platforms/wasm/qwasmscreen.cpp
+++ b/src/plugins/platforms/wasm/qwasmscreen.cpp
@@ -68,7 +68,8 @@ QWasmScreen::QWasmScreen(const emscripten::val &containerOrCanvas)
// Create the canvas (for the correct document) as a child of the container
m_canvas = containerOrCanvas["ownerDocument"].call<emscripten::val>("createElement", std::string("canvas"));
containerOrCanvas.call<void>("appendChild", m_canvas);
- m_canvas.set("id", std::string("qtcanvas_") + std::to_string(uint32_t(this)));
+ std::string screenId = std::string("qtcanvas_") + std::to_string(uint32_t(this));
+ m_canvas.set("id", screenId);
// Make the canvas occupy 100% of parent
emscripten::val style = m_canvas["style"];
@@ -96,6 +97,16 @@ QWasmScreen::QWasmScreen(const emscripten::val &containerOrCanvas)
m_onContextMenu = std::make_unique<qstdweb::EventCallback>(m_canvas, "contextmenu", [](emscripten::val event){
event.call<void>("preventDefault");
});
+
+ // Create "specialHTMLTargets" mapping for the canvas. Normally, Emscripten
+ // uses the html element id when targeting elements, for example when registering
+ // event callbacks. However, this approach is limited to supporting single-document
+ // 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.
+ EM_ASM({
+ specialHTMLTargets["!qtcanvas_" + $0] = Emval.toValue($1);
+ }, uint32_t(this), m_canvas.as_handle());
// Install event handlers on the container/canvas. This must be
// done after the canvas has been created above.
@@ -107,6 +118,10 @@ QWasmScreen::QWasmScreen(const emscripten::val &containerOrCanvas)
QWasmScreen::~QWasmScreen()
{
+ EM_ASM({
+ specialHTMLTargets["!qtcanvas_" + $0] = undefined;
+ }, uint32_t(this));
+
m_canvas.set(m_canvasResizeObserverCallbackContextPropertyName, emscripten::val(intptr_t(0)));
destroy();
}
@@ -146,11 +161,21 @@ emscripten::val QWasmScreen::canvas() const
return m_canvas;
}
+// Returns the html element id for the screen's canvas.
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.
+QString QWasmScreen::canvasTargetId() const
+{
+ return QStringLiteral("!qtcanvas_") + QString::number(int32_t(this));
+}
+
QRect QWasmScreen::geometry() const
{
return m_geometry;
@@ -246,7 +271,7 @@ void QWasmScreen::updateQScreenAndCanvasRenderSize()
// Setting the render size to a value larger than the CSS size enables high-dpi
// rendering.
- QByteArray canvasSelector = "#" + canvasId().toUtf8();
+ QByteArray canvasSelector = canvasTargetId().toUtf8();
double css_width;
double css_height;
emscripten_get_element_css_size(canvasSelector.constData(), &css_width, &css_height);
diff --git a/src/plugins/platforms/wasm/qwasmscreen.h b/src/plugins/platforms/wasm/qwasmscreen.h
index 4fb387f10a2..07f52f9fdcf 100644
--- a/src/plugins/platforms/wasm/qwasmscreen.h
+++ b/src/plugins/platforms/wasm/qwasmscreen.h
@@ -62,6 +62,7 @@ public:
emscripten::val container() const;
emscripten::val canvas() const;
QString canvasId() const;
+ QString canvasTargetId() const;
QWasmCompositor *compositor();
QWasmEventTranslator *eventTranslator();