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("createElement", std::string("canvas")); containerOrCanvas.call("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(m_canvas, "contextmenu", [](emscripten::val event){ event.call("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();