diff options
author | Morten Johan Sørvig <[email protected]> | 2021-11-27 23:56:40 +0100 |
---|---|---|
committer | Morten Johan Sørvig <[email protected]> | 2022-04-05 22:34:44 +0200 |
commit | 08733dff582e220ba381939e74c623a5321fb9a5 (patch) | |
tree | 11c8f3212489b555eea37ecd881724ed0f18ceb1 | |
parent | 4bc85b9850303fa20206f8774af88d72593d3454 (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.cpp | 4 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmopenglcontext.cpp | 7 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmscreen.cpp | 29 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmscreen.h | 1 |
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(); |