b9491daad0
This is a minimal version of qtloader. The load function accepts the same arguments as emscripten runtime with a few additions: - qt.environment - qt.onExit - qt.containerElements - qt.fontDpi - qt.onLoaded - qt.entryFunction State handling has been removed in favor of making the load async (assume loading when the promise is live). Public APIs getting crashed status, exit text and code have been refactored into the new qt.onExit event fed to load. No need for keeping the state in the loader. The loader is integration-tested. A test module with test APIs has been created as a test harness. The runtime APIs exposed by Qt (font dpi and screen API) are handled by the qtloader seamlessly. Change-Id: Iaee65702667da0349a475feae6b83244d966d98d Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
173 lines
4.4 KiB
C++
173 lines
4.4 KiB
C++
// Copyright (C) 2022 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
#include <QtCore/QEvent>
|
|
#include <QtCore/QObject>
|
|
#include <QtGui/qwindow.h>
|
|
#include <QtGui/qguiapplication.h>
|
|
#include <QtGui/qoffscreensurface.h>
|
|
#include <QtGui/qpa/qwindowsysteminterface.h>
|
|
#include <QtGui/rhi/qrhi.h>
|
|
|
|
#include <qtwasmtestlib.h>
|
|
|
|
#include <emscripten.h>
|
|
#include <emscripten/val.h>
|
|
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
namespace tst_qwasmcompositor_internal {
|
|
namespace {
|
|
class Window : public QWindow
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
Window();
|
|
~Window() override { qDebug() << "dtor Window"; }
|
|
|
|
void keyPressEvent(QKeyEvent *) final;
|
|
|
|
signals:
|
|
void exposed();
|
|
void keyEventReceived();
|
|
void initFailed();
|
|
|
|
protected:
|
|
private:
|
|
void init();
|
|
|
|
void exposeEvent(QExposeEvent *) override;
|
|
bool m_exposedOnce = false;
|
|
|
|
std::unique_ptr<QOffscreenSurface> m_fallbackSurface;
|
|
std::unique_ptr<QRhi> m_rhi;
|
|
};
|
|
|
|
Window::Window()
|
|
{
|
|
setSurfaceType(OpenGLSurface);
|
|
}
|
|
|
|
void Window::exposeEvent(QExposeEvent *)
|
|
{
|
|
if (isExposed() && !m_exposedOnce) {
|
|
m_exposedOnce = true;
|
|
init();
|
|
emit exposed();
|
|
}
|
|
}
|
|
|
|
void Window::keyPressEvent(QKeyEvent *)
|
|
{
|
|
emit keyEventReceived();
|
|
}
|
|
|
|
void Window::init()
|
|
{
|
|
QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers;
|
|
|
|
m_fallbackSurface.reset(QRhiGles2InitParams::newFallbackSurface());
|
|
QRhiGles2InitParams params;
|
|
params.fallbackSurface = m_fallbackSurface.get();
|
|
params.window = this;
|
|
|
|
// Double init of RHI causes the OpenGL context to be destroyed, which causes a bug with input.
|
|
m_rhi.reset(QRhi::create(QRhi::OpenGLES2, ¶ms, rhiFlags));
|
|
m_rhi.reset(QRhi::create(QRhi::OpenGLES2, ¶ms, rhiFlags));
|
|
|
|
if (!m_rhi)
|
|
emit initFailed();
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace tst_qwasmcompositor_internal
|
|
|
|
using namespace emscripten;
|
|
|
|
class QWasmCompositorTest : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
QWasmCompositorTest() : m_window(val::global("window")), m_testSupport(val::object())
|
|
{
|
|
m_window.set("testSupport", m_testSupport);
|
|
m_testSupport.set("qtSetContainerElements",
|
|
emscripten::val::module_property("qtSetContainerElements"));
|
|
}
|
|
|
|
~QWasmCompositorTest() noexcept
|
|
{
|
|
qDebug() << this << "In dtor";
|
|
for (auto it = m_cleanup.rbegin(); it != m_cleanup.rend(); ++it)
|
|
(*it)();
|
|
m_window.set("testSupport", emscripten::val::undefined());
|
|
}
|
|
|
|
private:
|
|
void init()
|
|
{
|
|
EM_ASM({
|
|
testSupport.screenElement = document.createElement("div");
|
|
testSupport.screenElement.id = "test-canvas-qwasmcompositor";
|
|
document.body.appendChild(testSupport.screenElement);
|
|
});
|
|
m_cleanup.emplace_back([]() mutable {
|
|
EM_ASM({
|
|
testSupport.qtSetContainerElements([]);
|
|
testSupport.screenElement.parentElement.removeChild(testSupport.screenElement);
|
|
});
|
|
});
|
|
|
|
EM_ASM({ testSupport.qtSetContainerElements([testSupport.screenElement]); });
|
|
}
|
|
|
|
template<class T>
|
|
T *Own(T *plainPtr)
|
|
{
|
|
m_cleanup.emplace_back([plainPtr]() mutable { delete plainPtr; });
|
|
return plainPtr;
|
|
}
|
|
|
|
val m_window;
|
|
val m_testSupport;
|
|
|
|
std::vector<std::function<void()>> m_cleanup;
|
|
|
|
private slots:
|
|
void testReceivingKeyboardEventsAfterOpenGLContextReset();
|
|
};
|
|
|
|
void QWasmCompositorTest::testReceivingKeyboardEventsAfterOpenGLContextReset()
|
|
{
|
|
init();
|
|
|
|
using Window = tst_qwasmcompositor_internal::Window;
|
|
Window *window = Own(new Window);
|
|
window->show();
|
|
window->requestActivate();
|
|
|
|
QWindowSystemInterface::flushWindowSystemEvents();
|
|
|
|
QObject::connect(window, &Window::keyEventReceived, []() { QWASMSUCCESS(); });
|
|
QObject::connect(window, &Window::initFailed,
|
|
[]() { QWASMFAIL("Cannot initialize test window"); });
|
|
QObject::connect(window, &Window::exposed, []() {
|
|
EM_ASM({
|
|
testSupport.screenElement.shadowRoot.querySelector('.qt-window')
|
|
.dispatchEvent(new KeyboardEvent('keydown', { key : 'a' }));
|
|
});
|
|
});
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
auto testObject = std::make_shared<QWasmCompositorTest>();
|
|
QtWasmTest::initTestCase<QGuiApplication>(argc, argv, testObject);
|
|
return 0;
|
|
}
|
|
|
|
#include "qwasmcompositor_main.moc"
|