wasm: store and pass canvases as emscripten::val
Store and pass canvases as emscripten::val instead of a QString containing the element id. This simplifies code which interacts with the canvas using the emscripten::val API, by removing the need to look up with getElementById. The Emscripten C event API does not accept emscripten::val, and using the element id is still needed here. emscripten::val does not provide a hash key suitable for use with QHash, but does provide an equality-compare in the form of val::equals(). Change the canvas->screen mapping code to use a QVector instead of a QHash. Change-Id: I1dbdbbc8fb06bb869031f1500e83ae2d64780a7f Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
This commit is contained in:
parent
e290ebae9f
commit
2b0af50c8b
@ -192,15 +192,12 @@ void QWasmClipboard::initClipboardEvents()
|
|||||||
permissions.call<val>("query", writePermissionsMap);
|
permissions.call<val>("query", writePermissionsMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWasmClipboard::installEventHandlers(const QString &canvasId)
|
void QWasmClipboard::installEventHandlers(const emscripten::val &canvas)
|
||||||
{
|
{
|
||||||
if (hasClipboardApi)
|
if (hasClipboardApi)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Fallback path for browsers which do not support direct clipboard access
|
// Fallback path for browsers which do not support direct clipboard access
|
||||||
val document = val::global("document");
|
|
||||||
val canvas = document.call<val>("getElementById", QWasmString::fromQString(canvasId));
|
|
||||||
|
|
||||||
canvas.call<void>("addEventListener", val("cut"),
|
canvas.call<void>("addEventListener", val("cut"),
|
||||||
val::module_property("qtClipboardCutTo"));
|
val::module_property("qtClipboardCutTo"));
|
||||||
canvas.call<void>("addEventListener", val("copy"),
|
canvas.call<void>("addEventListener", val("copy"),
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
|
|
||||||
#include <emscripten/bind.h>
|
#include <emscripten/bind.h>
|
||||||
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
class QWasmClipboard : public QObject, public QPlatformClipboard
|
class QWasmClipboard : public QObject, public QPlatformClipboard
|
||||||
{
|
{
|
||||||
@ -51,7 +52,7 @@ public:
|
|||||||
|
|
||||||
static void qWasmClipboardPaste(QMimeData *mData);
|
static void qWasmClipboardPaste(QMimeData *mData);
|
||||||
void initClipboardEvents();
|
void initClipboardEvents();
|
||||||
void installEventHandlers(const QString &canvasId);
|
void installEventHandlers(const emscripten::val &canvas);
|
||||||
bool hasClipboardApi;
|
bool hasClipboardApi;
|
||||||
void readTextFromClipboard();
|
void readTextFromClipboard();
|
||||||
void writeTextToClipboard();
|
void writeTextToClipboard();
|
||||||
|
@ -57,9 +57,7 @@ void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
|
|||||||
htmlCursorName = "auto";
|
htmlCursorName = "auto";
|
||||||
|
|
||||||
// Set cursor on the canvas
|
// Set cursor on the canvas
|
||||||
val jsCanvasId = QWasmString::fromQString(QWasmScreen::get(screen)->canvasId());
|
val canvas = QWasmScreen::get(screen)->canvas();
|
||||||
val document = val::global("document");
|
|
||||||
val canvas = document.call<val>("getElementById", jsCanvasId);
|
|
||||||
val canvasStyle = canvas["style"];
|
val canvasStyle = canvas["style"];
|
||||||
canvasStyle.set("cursor", val(htmlCursorName.constData()));
|
canvasStyle.set("cursor", val(htmlCursorName.constData()));
|
||||||
}
|
}
|
||||||
|
@ -354,9 +354,7 @@ void QWasmEventTranslator::initEventHandlers()
|
|||||||
g_useNaturalScrolling = false; // make this !default on macOS
|
g_useNaturalScrolling = false; // make this !default on macOS
|
||||||
|
|
||||||
if (emscripten::val::global("window")["safari"].isUndefined()) {
|
if (emscripten::val::global("window")["safari"].isUndefined()) {
|
||||||
val document = val::global("document");
|
val canvas = screen()->canvas();
|
||||||
val jsCanvasId = QWasmString::fromQString(screen()->canvasId());
|
|
||||||
val canvas = document.call<val>("getElementById", jsCanvasId);
|
|
||||||
canvas.call<void>("addEventListener",
|
canvas.call<void>("addEventListener",
|
||||||
val("wheel"),
|
val("wheel"),
|
||||||
val::module_property("qtMouseWheelEvent"));
|
val::module_property("qtMouseWheelEvent"));
|
||||||
|
@ -68,20 +68,17 @@ static void browserBeforeUnload(emscripten::val)
|
|||||||
|
|
||||||
static void addCanvasElement(emscripten::val canvas)
|
static void addCanvasElement(emscripten::val canvas)
|
||||||
{
|
{
|
||||||
QString canvasId = QWasmString::toQString(canvas["id"]);
|
QWasmIntegration::get()->addScreen(canvas);
|
||||||
QWasmIntegration::get()->addScreen(canvasId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void removeCanvasElement(emscripten::val canvas)
|
static void removeCanvasElement(emscripten::val canvas)
|
||||||
{
|
{
|
||||||
QString canvasId = QWasmString::toQString(canvas["id"]);
|
QWasmIntegration::get()->removeScreen(canvas);
|
||||||
QWasmIntegration::get()->removeScreen(canvasId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void resizeCanvasElement(emscripten::val canvas)
|
static void resizeCanvasElement(emscripten::val canvas)
|
||||||
{
|
{
|
||||||
QString canvasId = QWasmString::toQString(canvas["id"]);
|
QWasmIntegration::get()->resizeScreen(canvas);
|
||||||
QWasmIntegration::get()->resizeScreen(canvasId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qtUpdateDpi()
|
static void qtUpdateDpi()
|
||||||
@ -114,15 +111,12 @@ QWasmIntegration::QWasmIntegration()
|
|||||||
if (!qtCanvaseElements.isUndefined()) {
|
if (!qtCanvaseElements.isUndefined()) {
|
||||||
int screenCount = qtCanvaseElements["length"].as<int>();
|
int screenCount = qtCanvaseElements["length"].as<int>();
|
||||||
for (int i = 0; i < screenCount; ++i) {
|
for (int i = 0; i < screenCount; ++i) {
|
||||||
emscripten::val canvas = qtCanvaseElements[i].as<emscripten::val>();
|
addScreen(qtCanvaseElements[i].as<emscripten::val>());
|
||||||
QString canvasId = QWasmString::toQString(canvas["id"]);
|
|
||||||
addScreen(canvasId);
|
|
||||||
}
|
}
|
||||||
} else if (!canvas.isUndefined()) {
|
} else if (!canvas.isUndefined()) {
|
||||||
qWarning() << "Module.canvas is deprecated. A future version of Qt will stop reading this property. "
|
qWarning() << "Module.canvas is deprecated. A future version of Qt will stop reading this property. "
|
||||||
<< "Instead, set Module.qtCanvasElements to be an array of canvas elements, or use qtloader.js.";
|
<< "Instead, set Module.qtCanvasElements to be an array of canvas elements, or use qtloader.js.";
|
||||||
QString canvasId = QWasmString::toQString(canvas["id"]);
|
addScreen(canvas);
|
||||||
addScreen(canvasId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emscripten::val::global("window").set("onbeforeunload", val::module_property("qtBrowserBeforeUnload"));
|
emscripten::val::global("window").set("onbeforeunload", val::module_property("qtBrowserBeforeUnload"));
|
||||||
@ -148,8 +142,8 @@ QWasmIntegration::~QWasmIntegration()
|
|||||||
delete m_fontDb;
|
delete m_fontDb;
|
||||||
delete m_desktopServices;
|
delete m_desktopServices;
|
||||||
|
|
||||||
for (auto it = m_screens.constBegin(); it != m_screens.constEnd(); ++it)
|
for (const auto &canvasAndScreen : m_screens)
|
||||||
QWindowSystemInterface::handleScreenRemoved(*it);
|
QWindowSystemInterface::handleScreenRemoved(canvasAndScreen.second);
|
||||||
m_screens.clear();
|
m_screens.clear();
|
||||||
|
|
||||||
s_instance = nullptr;
|
s_instance = nullptr;
|
||||||
@ -271,24 +265,37 @@ QPlatformClipboard* QWasmIntegration::clipboard() const
|
|||||||
return m_clipboard;
|
return m_clipboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWasmIntegration::addScreen(const QString &canvasId)
|
void QWasmIntegration::addScreen(const emscripten::val &canvas)
|
||||||
{
|
{
|
||||||
QWasmScreen *screen = new QWasmScreen(canvasId);
|
QWasmScreen *screen = new QWasmScreen(canvas);
|
||||||
m_clipboard->installEventHandlers(canvasId);
|
m_screens.append(qMakePair(canvas, screen));
|
||||||
m_screens.insert(canvasId, screen);
|
m_clipboard->installEventHandlers(canvas);
|
||||||
QWindowSystemInterface::handleScreenAdded(screen);
|
QWindowSystemInterface::handleScreenAdded(screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWasmIntegration::removeScreen(const QString &canvasId)
|
void QWasmIntegration::removeScreen(const emscripten::val &canvas)
|
||||||
{
|
{
|
||||||
QWasmScreen *exScreen = m_screens.take(canvasId);
|
auto it = std::find_if(m_screens.begin(), m_screens.end(),
|
||||||
|
[&] (const QPair<emscripten::val, QWasmScreen *> &candidate) { return candidate.first.equals(canvas); });
|
||||||
|
if (it == m_screens.end()) {
|
||||||
|
qWarning() << "Attempting to remove non-existing screen for canvas" << QWasmString::toQString(canvas["id"]);;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QWasmScreen *exScreen = it->second;
|
||||||
|
m_screens.erase(it);
|
||||||
exScreen->destroy(); // clean up before deleting the screen
|
exScreen->destroy(); // clean up before deleting the screen
|
||||||
QWindowSystemInterface::handleScreenRemoved(exScreen);
|
QWindowSystemInterface::handleScreenRemoved(exScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWasmIntegration::resizeScreen(const QString &canvasId)
|
void QWasmIntegration::resizeScreen(const emscripten::val &canvas)
|
||||||
{
|
{
|
||||||
m_screens.value(canvasId)->updateQScreenAndCanvasRenderSize();
|
auto it = std::find_if(m_screens.begin(), m_screens.end(),
|
||||||
|
[&] (const QPair<emscripten::val, QWasmScreen *> &candidate) { return candidate.first.equals(canvas); });
|
||||||
|
if (it == m_screens.end()) {
|
||||||
|
qWarning() << "Attempting to resize non-existing screen for canvas" << QWasmString::toQString(canvas["id"]);;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
it->second->updateQScreenAndCanvasRenderSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWasmIntegration::updateDpi()
|
void QWasmIntegration::updateDpi()
|
||||||
@ -297,15 +304,14 @@ void QWasmIntegration::updateDpi()
|
|||||||
if (dpi.isUndefined())
|
if (dpi.isUndefined())
|
||||||
return;
|
return;
|
||||||
qreal dpiValue = dpi.as<qreal>();
|
qreal dpiValue = dpi.as<qreal>();
|
||||||
for (QWasmScreen *screen : m_screens)
|
for (const auto &canvasAndScreen : m_screens)
|
||||||
QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen->screen(), dpiValue, dpiValue);
|
QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(canvasAndScreen.second->screen(), dpiValue, dpiValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWasmIntegration::resizeAllScreens()
|
void QWasmIntegration::resizeAllScreens()
|
||||||
{
|
{
|
||||||
qDebug() << "resizeAllScreens";
|
for (const auto &canvasAndScreen : m_screens)
|
||||||
for (QWasmScreen *screen : m_screens)
|
canvasAndScreen.second->updateQScreenAndCanvasRenderSize();
|
||||||
screen->updateQScreenAndCanvasRenderSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
#include <emscripten/html5.h>
|
#include <emscripten/html5.h>
|
||||||
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -83,9 +84,9 @@ public:
|
|||||||
static QWasmIntegration *get() { return s_instance; }
|
static QWasmIntegration *get() { return s_instance; }
|
||||||
static void QWasmBrowserExit();
|
static void QWasmBrowserExit();
|
||||||
|
|
||||||
void addScreen(const QString &canvasId);
|
void addScreen(const emscripten::val &canvas);
|
||||||
void removeScreen(const QString &canvasId);
|
void removeScreen(const emscripten::val &canvas);
|
||||||
void resizeScreen(const QString &canvasId);
|
void resizeScreen(const emscripten::val &canvas);
|
||||||
void resizeAllScreens();
|
void resizeAllScreens();
|
||||||
void updateDpi();
|
void updateDpi();
|
||||||
|
|
||||||
@ -93,8 +94,7 @@ private:
|
|||||||
mutable QWasmFontDatabase *m_fontDb;
|
mutable QWasmFontDatabase *m_fontDb;
|
||||||
mutable QWasmServices *m_desktopServices;
|
mutable QWasmServices *m_desktopServices;
|
||||||
mutable QHash<QWindow *, QWasmBackingStore *> m_backingStores;
|
mutable QHash<QWindow *, QWasmBackingStore *> m_backingStores;
|
||||||
|
QVector<QPair<emscripten::val, QWasmScreen *>> m_screens;
|
||||||
QHash<QString, QWasmScreen *> m_screens;
|
|
||||||
mutable QWasmClipboard *m_clipboard;
|
mutable QWasmClipboard *m_clipboard;
|
||||||
qreal m_fontDpi = -1;
|
qreal m_fontDpi = -1;
|
||||||
mutable QScopedPointer<QPlatformInputContext> m_inputContext;
|
mutable QScopedPointer<QPlatformInputContext> m_inputContext;
|
||||||
|
@ -50,15 +50,13 @@ using namespace emscripten;
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
QWasmScreen::QWasmScreen(const QString &canvasId)
|
QWasmScreen::QWasmScreen(const emscripten::val &canvas)
|
||||||
: m_canvasId(canvasId)
|
: m_canvas(canvas)
|
||||||
|
|
||||||
{
|
{
|
||||||
m_compositor = new QWasmCompositor(this);
|
m_compositor = new QWasmCompositor(this);
|
||||||
m_eventTranslator = new QWasmEventTranslator(this);
|
m_eventTranslator = new QWasmEventTranslator(this);
|
||||||
updateQScreenAndCanvasRenderSize();
|
updateQScreenAndCanvasRenderSize();
|
||||||
emscripten::val canvas = emscripten::val::global(m_canvasId.toUtf8().constData());
|
m_canvas.call<void>("focus");
|
||||||
canvas.call<void>("focus");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QWasmScreen::~QWasmScreen()
|
QWasmScreen::~QWasmScreen()
|
||||||
@ -91,9 +89,14 @@ QWasmEventTranslator *QWasmScreen::eventTranslator()
|
|||||||
return m_eventTranslator;
|
return m_eventTranslator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emscripten::val QWasmScreen::canvas() const
|
||||||
|
{
|
||||||
|
return m_canvas;
|
||||||
|
}
|
||||||
|
|
||||||
QString QWasmScreen::canvasId() const
|
QString QWasmScreen::canvasId() const
|
||||||
{
|
{
|
||||||
return m_canvasId;
|
return QWasmString::toQString(m_canvas["id"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
QRect QWasmScreen::geometry() const
|
QRect QWasmScreen::geometry() const
|
||||||
@ -134,7 +137,7 @@ qreal QWasmScreen::devicePixelRatio() const
|
|||||||
|
|
||||||
QString QWasmScreen::name() const
|
QString QWasmScreen::name() const
|
||||||
{
|
{
|
||||||
return m_canvasId;
|
return canvasId();
|
||||||
}
|
}
|
||||||
|
|
||||||
QPlatformCursor *QWasmScreen::cursor() const
|
QPlatformCursor *QWasmScreen::cursor() const
|
||||||
@ -180,24 +183,22 @@ void QWasmScreen::updateQScreenAndCanvasRenderSize()
|
|||||||
// Setting the render size to a value larger than the CSS size enables high-dpi
|
// Setting the render size to a value larger than the CSS size enables high-dpi
|
||||||
// rendering.
|
// rendering.
|
||||||
|
|
||||||
QByteArray canvasSelector = "#" + m_canvasId.toUtf8();
|
QByteArray canvasSelector = "#" + canvasId().toUtf8();
|
||||||
double css_width;
|
double css_width;
|
||||||
double css_height;
|
double css_height;
|
||||||
emscripten_get_element_css_size(canvasSelector.constData(), &css_width, &css_height);
|
emscripten_get_element_css_size(canvasSelector.constData(), &css_width, &css_height);
|
||||||
QSizeF cssSize(css_width, css_height);
|
QSizeF cssSize(css_width, css_height);
|
||||||
|
|
||||||
QSizeF canvasSize = cssSize * devicePixelRatio();
|
QSizeF canvasSize = cssSize * devicePixelRatio();
|
||||||
val document = val::global("document");
|
|
||||||
val canvas = document.call<val>("getElementById", QWasmString::fromQString(m_canvasId));
|
|
||||||
|
|
||||||
canvas.set("width", canvasSize.width());
|
m_canvas.set("width", canvasSize.width());
|
||||||
canvas.set("height", canvasSize.height());
|
m_canvas.set("height", canvasSize.height());
|
||||||
|
|
||||||
QPoint offset;
|
QPoint offset;
|
||||||
offset.setX(canvas["offsetTop"].as<int>());
|
offset.setX(m_canvas["offsetTop"].as<int>());
|
||||||
offset.setY(canvas["offsetLeft"].as<int>());
|
offset.setY(m_canvas["offsetLeft"].as<int>());
|
||||||
|
|
||||||
emscripten::val rect = canvas.call<emscripten::val>("getBoundingClientRect");
|
emscripten::val rect = m_canvas.call<emscripten::val>("getBoundingClientRect");
|
||||||
QPoint position(rect["left"].as<int>() - offset.x(), rect["top"].as<int>() - offset.y());
|
QPoint position(rect["left"].as<int>() - offset.x(), rect["top"].as<int>() - offset.y());
|
||||||
|
|
||||||
setGeometry(QRect(position, cssSize.toSize()));
|
setGeometry(QRect(position, cssSize.toSize()));
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
#include <QtCore/qscopedpointer.h>
|
#include <QtCore/qscopedpointer.h>
|
||||||
#include <QtCore/qtextstream.h>
|
#include <QtCore/qtextstream.h>
|
||||||
|
|
||||||
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QPlatformOpenGLContext;
|
class QPlatformOpenGLContext;
|
||||||
@ -50,12 +52,13 @@ class QWasmScreen : public QObject, public QPlatformScreen
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
QWasmScreen(const QString &canvasId);
|
QWasmScreen(const emscripten::val &canvas);
|
||||||
~QWasmScreen();
|
~QWasmScreen();
|
||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
static QWasmScreen *get(QPlatformScreen *screen);
|
static QWasmScreen *get(QPlatformScreen *screen);
|
||||||
static QWasmScreen *get(QScreen *screen);
|
static QWasmScreen *get(QScreen *screen);
|
||||||
|
emscripten::val canvas() const;
|
||||||
QString canvasId() const;
|
QString canvasId() const;
|
||||||
|
|
||||||
QWasmCompositor *compositor();
|
QWasmCompositor *compositor();
|
||||||
@ -80,7 +83,7 @@ public slots:
|
|||||||
void setGeometry(const QRect &rect);
|
void setGeometry(const QRect &rect);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_canvasId;
|
emscripten::val m_canvas;
|
||||||
QWasmCompositor *m_compositor = nullptr;
|
QWasmCompositor *m_compositor = nullptr;
|
||||||
QWasmEventTranslator *m_eventTranslator = nullptr;
|
QWasmEventTranslator *m_eventTranslator = nullptr;
|
||||||
QRect m_geometry = QRect(0, 0, 100, 100);
|
QRect m_geometry = QRect(0, 0, 100, 100);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user