wasm: Improve screen cleanup

Fix the use case where the application recreates the
QApplication object while reusing the html container
element. This would cause an error:

  Uncaught DOMException: Failed to execute 'attachShadow' on
  'Element': Shadow root cannot be created on a host which
  already hosts a shadow tree

It looks like there is no way to remove a previously
attached shadow root, which means we can't return the
container element to its initial state if we attach
to the user-provided container element.

Fix this by introducing an intermediate element which
we can remove() in the QWasmScreen destructor.

Pick-to: 6.6 6.5
Change-Id: I929393a498b0440390a3e2c1774a3cac3a5a7e79
Reviewed-by: Piotr Wierciński <piotr.wiercinski@qt.io>
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
bb10
Morten Sørvig 2023-09-12 17:59:09 +02:00 committed by Morten Johan Sørvig
parent 201c30986b
commit 0e23865c9e
2 changed files with 16 additions and 1 deletions

View File

@ -28,6 +28,7 @@ const char *QWasmScreen::m_canvasResizeObserverCallbackContextPropertyName =
QWasmScreen::QWasmScreen(const emscripten::val &containerOrCanvas)
: m_container(containerOrCanvas),
m_intermediateContainer(emscripten::val::undefined()),
m_shadowContainer(emscripten::val::undefined()),
m_compositor(new QWasmCompositor(this)),
m_deadKeySupport(std::make_unique<QWasmDeadKeySupport>())
@ -43,9 +44,20 @@ QWasmScreen::QWasmScreen(const emscripten::val &containerOrCanvas)
m_container["parentNode"].call<void>("replaceChild", container, m_container);
m_container = container;
}
// Create an intermediate container which we can remove during cleanup in ~QWasmScreen().
// This is required due to the attachShadow() call below; there is no corresponding
// "detachShadow()" API to return the container to its previous state.
m_intermediateContainer = document.call<emscripten::val>("createElement", emscripten::val("div"));
m_intermediateContainer.set("id", std::string("qt-shadow-container"));
emscripten::val intermediateContainerStyle = m_intermediateContainer["style"];
intermediateContainerStyle.set("width", std::string("100%"));
intermediateContainerStyle.set("height", std::string("100%"));
m_container.call<void>("appendChild", m_intermediateContainer);
auto shadowOptions = emscripten::val::object();
shadowOptions.set("mode", "open");
auto shadow = m_container.call<emscripten::val>("attachShadow", shadowOptions);
auto shadow = m_intermediateContainer.call<emscripten::val>("attachShadow", shadowOptions);
m_shadowContainer = document.call<emscripten::val>("createElement", emscripten::val("div"));
@ -86,6 +98,8 @@ QWasmScreen::QWasmScreen(const emscripten::val &containerOrCanvas)
QWasmScreen::~QWasmScreen()
{
m_intermediateContainer.call<void>("remove");
emscripten::val::module_property("specialHTMLTargets")
.set(eventTargetId().toStdString(), emscripten::val::undefined());

View File

@ -78,6 +78,7 @@ private:
QWasmWindow *child) final;
emscripten::val m_container;
emscripten::val m_intermediateContainer;
emscripten::val m_shadowContainer;
std::unique_ptr<QWasmCompositor> m_compositor;
std::unique_ptr<QPointingDevice> m_touchDevice;