/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 or (at your option) any later version ** approved by the KDE Free Qt Foundation. The licenses are as published by ** the Free Software Foundation and appearing in the file LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qwasmintegration.h" #include "qwasmeventtranslator.h" #include "qwasmeventdispatcher.h" #include "qwasmcompositor.h" #include "qwasmopenglcontext.h" #include "qwasmtheme.h" #include "qwasmwindow.h" #ifndef QT_NO_OPENGL # include "qwasmbackingstore.h" #endif #include "qwasmfontdatabase.h" #if defined(Q_OS_UNIX) #include #endif #include #include #include #include #include // this is where EGL headers are pulled in, make sure it is last #include "qwasmscreen.h" using namespace emscripten; QT_BEGIN_NAMESPACE void browserBeforeUnload() { QWasmIntegration::QWasmBrowserExit(); } EMSCRIPTEN_BINDINGS(my_module) { function("browserBeforeUnload", &browserBeforeUnload); } static QWasmIntegration *globalHtml5Integration; QWasmIntegration *QWasmIntegration::get() { return globalHtml5Integration; } void emscriptenOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { int emOutputFlags = (EM_LOG_CONSOLE | EM_LOG_DEMANGLE); QByteArray localMsg = msg.toLocal8Bit(); switch (type) { case QtDebugMsg: emscripten_log(emOutputFlags, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); break; case QtInfoMsg: emscripten_log(emOutputFlags, "Info: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); break; case QtWarningMsg: emOutputFlags |= EM_LOG_WARN; emscripten_log(emOutputFlags, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); break; case QtCriticalMsg: emOutputFlags |= EM_LOG_ERROR; emscripten_log(emOutputFlags, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); break; case QtFatalMsg: emOutputFlags |= EM_LOG_ERROR; emscripten_log(emOutputFlags, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); abort(); } } QWasmIntegration::QWasmIntegration() : mFontDb(nullptr), mCompositor(new QWasmCompositor), mScreen(new QWasmScreen(mCompositor)), m_eventDispatcher(nullptr) { qSetMessagePattern(QString("(%{function}:%{line}) - %{message}")); qInstallMessageHandler(emscriptenOutput); globalHtml5Integration = this; updateQScreenAndCanvasRenderSize(); screenAdded(mScreen); emscripten_set_resize_callback(0, (void *)this, 1, uiEvent_cb); m_eventTranslator = new QWasmEventTranslator(); EM_ASM(// exit app if browser closes window.onbeforeunload = function () { Module.browserBeforeUnload(); }; ); } QWasmIntegration::~QWasmIntegration() { delete mCompositor; destroyScreen(mScreen); delete mFontDb; delete m_eventTranslator; } void QWasmIntegration::QWasmBrowserExit() { QCoreApplication *app = QCoreApplication::instance(); app->quit(); } bool QWasmIntegration::hasCapability(QPlatformIntegration::Capability cap) const { switch (cap) { case ThreadedPixmaps: return true; case OpenGL: return true; case ThreadedOpenGL: return true; case RasterGLSurface: return true; case MultipleWindows: return true; case WindowManagement: return true; default: return QPlatformIntegration::hasCapability(cap); } } QPlatformWindow *QWasmIntegration::createPlatformWindow(QWindow *window) const { QWasmWindow *w = new QWasmWindow(window, mCompositor, m_backingStores.value(window)); w->create(); return w; } QPlatformBackingStore *QWasmIntegration::createPlatformBackingStore(QWindow *window) const { #ifndef QT_NO_OPENGL QWasmBackingStore *backingStore = new QWasmBackingStore(mCompositor, window); m_backingStores.insert(window, backingStore); return backingStore; #else return nullptr; #endif } #ifndef QT_NO_OPENGL QPlatformOpenGLContext *QWasmIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { return new QWasmOpenGLContext(context->format()); } #endif QPlatformFontDatabase *QWasmIntegration::fontDatabase() const { if (mFontDb == 0) mFontDb = new QWasmFontDatabase(); return mFontDb; } QAbstractEventDispatcher *QWasmIntegration::createEventDispatcher() const { return new QWasmEventDispatcher(); } QVariant QWasmIntegration::styleHint(QPlatformIntegration::StyleHint hint) const { return QPlatformIntegration::styleHint(hint); } QStringList QWasmIntegration::themeNames() const { return QStringList() << QLatin1String("webassembly"); } QPlatformTheme *QWasmIntegration::createPlatformTheme(const QString &name) const { if (name == QLatin1String("webassembly")) return new QWasmTheme(); return QPlatformIntegration::createPlatformTheme(name); } int QWasmIntegration::uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData) { Q_UNUSED(e) Q_UNUSED(userData) if (eventType == EMSCRIPTEN_EVENT_RESIZE) { // This resize event is called when the HTML window is resized. Depending // on the page layout the the canvas might also have been resized, so we // update the Qt screen size (and canvas render size). updateQScreenAndCanvasRenderSize(); } return 0; } static void set_canvas_size(double width, double height) { EM_ASM_({ var canvas = Module.canvas; canvas.width = $0; canvas.height = $1; }, width, height); } void QWasmIntegration::updateQScreenAndCanvasRenderSize() { // The HTML canvas has two sizes: the CSS size and the canvas render size. // The CSS size is determined according to standard CSS rules, while the // render size is set using the "width" and "height" attributes. The render // size must be set manually and is not auto-updated on CSS size change. // Setting the render size to a value larger than the CSS size enables high-dpi // rendering. double css_width; double css_height; emscripten_get_element_css_size(0, &css_width, &css_height); QSizeF cssSize(css_width, css_height); QWasmScreen *screen = QWasmIntegration::get()->mScreen; QSizeF canvasSize = cssSize * screen->devicePixelRatio(); set_canvas_size(canvasSize.width(), canvasSize.height()); screen->setGeometry(QRect(QPoint(0, 0), cssSize.toSize())); QWasmIntegration::get()->mCompositor->redrawWindowContent(); } QT_END_NAMESPACE