summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLorn Potter <[email protected]>2023-10-11 09:41:11 +1000
committerLorn Potter <[email protected]>2023-12-21 14:04:57 +1000
commit5af9c3d0e7e244009ffb4195ebcffb32101d8f04 (patch)
tree225791ebac1c118677c33e087a5ec78cad847c01
parentc3a2b9f35a9a12ff3c6f5f0d11844de161b47c2a (diff)
wasm: move DataTransfer to dom::
Change-Id: I069292154bafd1c08a0d0f2e8a62052f596a80f3 Done-with: [email protected] Reviewed-by: Lorn Potter <[email protected]>
-rw-r--r--src/corelib/platform/wasm/qstdweb.cpp113
-rw-r--r--src/corelib/platform/wasm/qstdweb_p.h5
-rw-r--r--src/plugins/platforms/wasm/qwasmclipboard.cpp28
-rw-r--r--src/plugins/platforms/wasm/qwasmclipboard.h1
-rw-r--r--src/plugins/platforms/wasm/qwasmdom.cpp140
-rw-r--r--src/plugins/platforms/wasm/qwasmdom.h28
-rw-r--r--src/plugins/platforms/wasm/qwasmevent.h3
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.cpp33
8 files changed, 194 insertions, 157 deletions
diff --git a/src/corelib/platform/wasm/qstdweb.cpp b/src/corelib/platform/wasm/qstdweb.cpp
index 38ade571bda..2de5fca0402 100644
--- a/src/corelib/platform/wasm/qstdweb.cpp
+++ b/src/corelib/platform/wasm/qstdweb.cpp
@@ -376,112 +376,6 @@ bool jsHaveAsyncify() { return false; }
bool jsHaveJspi() { return false; }
#endif
-
-struct DataTransferReader
-{
-public:
- using DoneCallback = std::function<void(std::unique_ptr<QMimeData>)>;
-
- static std::shared_ptr<CancellationFlag> read(emscripten::val webDataTransfer,
- std::function<QVariant(QByteArray)> imageReader,
- DoneCallback onCompleted)
- {
- auto cancellationFlag = std::make_shared<CancellationFlag>();
- (new DataTransferReader(std::move(onCompleted), std::move(imageReader), cancellationFlag))
- ->read(webDataTransfer);
- return cancellationFlag;
- }
-
- ~DataTransferReader() = default;
-
-private:
- DataTransferReader(DoneCallback onCompleted, std::function<QVariant(QByteArray)> imageReader,
- std::shared_ptr<CancellationFlag> cancellationFlag)
- : mimeData(std::make_unique<QMimeData>()),
- imageReader(std::move(imageReader)),
- onCompleted(std::move(onCompleted)),
- cancellationFlag(cancellationFlag)
- {
- }
-
- void read(emscripten::val webDataTransfer)
- {
- enum class ItemKind {
- File,
- String,
- };
-
- const auto items = webDataTransfer["items"];
- for (int i = 0; i < items["length"].as<int>(); ++i) {
- const auto item = items[i];
- const auto itemKind =
- item["kind"].as<std::string>() == "string" ? ItemKind::String : ItemKind::File;
- const auto itemMimeType = QString::fromStdString(item["type"].as<std::string>());
-
- switch (itemKind) {
- case ItemKind::File: {
- ++fileCount;
-
- qstdweb::File file(item.call<emscripten::val>("getAsFile"));
-
- QByteArray fileContent(file.size(), Qt::Uninitialized);
- file.stream(fileContent.data(), [this, itemMimeType, fileContent]() {
- if (!fileContent.isEmpty()) {
- if (itemMimeType.startsWith("image/"_L1)) {
- mimeData->setImageData(imageReader(fileContent));
- } else {
- mimeData->setData(itemMimeType, fileContent.data());
- }
- }
- ++doneCount;
- onFileRead();
- });
- break;
- }
- case ItemKind::String:
- if (itemMimeType.contains("STRING"_L1, Qt::CaseSensitive)
- || itemMimeType.contains("TEXT"_L1, Qt::CaseSensitive)) {
- break;
- }
- QString a;
- const QString data = QString::fromEcmaString(webDataTransfer.call<emscripten::val>(
- "getData", emscripten::val(itemMimeType.toStdString())));
-
- if (!data.isEmpty()) {
- if (itemMimeType == "text/html"_L1)
- mimeData->setHtml(data);
- else if (itemMimeType.isEmpty() || itemMimeType == "text/plain"_L1)
- mimeData->setText(data); // the type can be empty
- else
- mimeData->setData(itemMimeType, data.toLocal8Bit());
- }
- break;
- }
- }
-
- onFileRead();
- }
-
- void onFileRead()
- {
- Q_ASSERT(doneCount <= fileCount);
- if (doneCount < fileCount)
- return;
-
- std::unique_ptr<DataTransferReader> deleteThisLater(this);
- if (!cancellationFlag.expired())
- onCompleted(std::move(mimeData));
- }
-
- int fileCount = 0;
- int doneCount = 0;
- std::unique_ptr<QMimeData> mimeData;
- std::function<QVariant(QByteArray)> imageReader;
- DoneCallback onCompleted;
-
- std::weak_ptr<CancellationFlag> cancellationFlag;
-};
-
} // namespace
ArrayBuffer::ArrayBuffer(uint32_t size)
@@ -948,13 +842,6 @@ bool canBlockCallingThread()
return haveAsyncify() || !emscripten_is_main_runtime_thread();
}
-std::shared_ptr<CancellationFlag>
-readDataTransfer(emscripten::val webDataTransfer, std::function<QVariant(QByteArray)> imageReader,
- std::function<void(std::unique_ptr<QMimeData>)> onDone)
-{
- return DataTransferReader::read(webDataTransfer, std::move(imageReader), std::move(onDone));
-}
-
BlobIODevice::BlobIODevice(Blob blob)
: m_blob(blob)
{
diff --git a/src/corelib/platform/wasm/qstdweb_p.h b/src/corelib/platform/wasm/qstdweb_p.h
index 110e2c10ac4..707d96704b3 100644
--- a/src/corelib/platform/wasm/qstdweb_p.h
+++ b/src/corelib/platform/wasm/qstdweb_p.h
@@ -290,11 +290,6 @@ namespace qstdweb {
{
};
- Q_CORE_EXPORT std::shared_ptr<CancellationFlag>
- readDataTransfer(emscripten::val webObject, std::function<QVariant(QByteArray)> imageReader,
- std::function<void(std::unique_ptr<QMimeData>)> onDone);
-
-
#if QT_CONFIG(thread)
template<class T>
T proxyCall(std::function<T()> task, emscripten::ProxyingQueue *queue)
diff --git a/src/plugins/platforms/wasm/qwasmclipboard.cpp b/src/plugins/platforms/wasm/qwasmclipboard.cpp
index 8916a946d4a..9c7088067eb 100644
--- a/src/plugins/platforms/wasm/qwasmclipboard.cpp
+++ b/src/plugins/platforms/wasm/qwasmclipboard.cpp
@@ -71,24 +71,15 @@ static void qClipboardPasteTo(val event)
event.call<void>("preventDefault"); // prevent browser from handling drop event
static std::shared_ptr<qstdweb::CancellationFlag> readDataCancellation = nullptr;
- readDataCancellation = qstdweb::readDataTransfer(
- event["clipboardData"],
- [](QByteArray fileContent) {
- QImage image;
- image.loadFromData(fileContent, nullptr);
- return image;
- },
- [event](std::unique_ptr<QMimeData> data) {
- if (data->formats().isEmpty())
- return;
-
- // Persist clipboard data so that the app can read it when handling the CTRL+V
- QWasmIntegration::get()->clipboard()->QPlatformClipboard::setMimeData(
- data.release(), QClipboard::Clipboard);
-
- QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, Qt::Key_V,
- Qt::ControlModifier, "V");
- });
+ dom::DataTransfer transfer(event["clipboardData"]);
+ auto data = transfer.toMimeDataWithFile();
+ if (data->formats().isEmpty())
+ return;
+ // Persist clipboard data so that the app can read it when handling the CTRL+V
+ QWasmIntegration::get()->clipboard()->QPlatformClipboard::setMimeData(data,
+ QClipboard::Clipboard);
+ QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, Qt::Key_V,
+ Qt::ControlModifier, "V");
}
EMSCRIPTEN_BINDINGS(qtClipboardModule) {
@@ -300,4 +291,5 @@ void QWasmClipboard::writeToClipboard()
val document = val::global("document");
document.call<val>("execCommand", val("copy"));
}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmclipboard.h b/src/plugins/platforms/wasm/qwasmclipboard.h
index 4a21252c8ed..11e7e9f714d 100644
--- a/src/plugins/platforms/wasm/qwasmclipboard.h
+++ b/src/plugins/platforms/wasm/qwasmclipboard.h
@@ -7,6 +7,7 @@
#include <QObject>
#include <qpa/qplatformclipboard.h>
+#include <private/qstdweb_p.h>
#include <QMimeData>
#include <emscripten/bind.h>
diff --git a/src/plugins/platforms/wasm/qwasmdom.cpp b/src/plugins/platforms/wasm/qwasmdom.cpp
index ebb2dd4807a..845aef3bc10 100644
--- a/src/plugins/platforms/wasm/qwasmdom.cpp
+++ b/src/plugins/platforms/wasm/qwasmdom.cpp
@@ -8,12 +8,152 @@
#include <QtCore/qrect.h>
#include <QtGui/qimage.h>
#include <private/qstdweb_p.h>
+#include <QtCore/qurl.h>
#include <utility>
+#include <emscripten/wire.h>
QT_BEGIN_NAMESPACE
namespace dom {
+namespace {
+std::string dropActionToDropEffect(Qt::DropAction action)
+{
+ switch (action) {
+ case Qt::DropAction::CopyAction:
+ return "copy";
+ case Qt::DropAction::IgnoreAction:
+ return "none";
+ case Qt::DropAction::LinkAction:
+ return "link";
+ case Qt::DropAction::MoveAction:
+ case Qt::DropAction::TargetMoveAction:
+ return "move";
+ case Qt::DropAction::ActionMask:
+ Q_ASSERT(false);
+ return "";
+ }
+}
+} // namespace
+
+DataTransfer::DataTransfer(emscripten::val webDataTransfer) : webDataTransfer(webDataTransfer) { }
+
+DataTransfer::~DataTransfer() = default;
+
+DataTransfer::DataTransfer(const DataTransfer &other) = default;
+
+DataTransfer::DataTransfer(DataTransfer &&other) = default;
+
+DataTransfer &DataTransfer::operator=(const DataTransfer &other) = default;
+
+DataTransfer &DataTransfer::operator=(DataTransfer &&other) = default;
+
+void DataTransfer::setDragImage(emscripten::val element, const QPoint &hotspot)
+{
+ webDataTransfer.call<void>("setDragImage", element, emscripten::val(hotspot.x()),
+ emscripten::val(hotspot.y()));
+}
+
+void DataTransfer::setData(std::string format, std::string data)
+{
+ webDataTransfer.call<void>("setData", emscripten::val(std::move(format)),
+ emscripten::val(std::move(data)));
+}
+
+void DataTransfer::setDropAction(Qt::DropAction action)
+{
+ webDataTransfer.set("dropEffect", emscripten::val(dropActionToDropEffect(action)));
+}
+
+void DataTransfer::setDataFromMimeData(const QMimeData &mimeData)
+{
+ for (const auto &format : mimeData.formats()) {
+ auto data = mimeData.data(format);
+
+ auto encoded = format.startsWith("text/")
+ ? QString::fromLocal8Bit(data).toStdString()
+ : "QB64" + QString::fromLocal8Bit(data.toBase64()).toStdString();
+
+ setData(format.toStdString(), std::move(encoded));
+ }
+}
+
+QMimeData *DataTransfer::toMimeDataWithFile()
+{
+ QMimeData *resultMimeData = new QMimeData(); // QScopedPointer?
+
+ enum class ItemKind {
+ File,
+ String,
+ };
+
+ const auto items = webDataTransfer["items"];
+ QList<QUrl> uriList;
+ for (int i = 0; i < items["length"].as<int>(); ++i) {
+ const auto item = items[i];
+ const auto itemKind =
+ item["kind"].as<std::string>() == "string" ? ItemKind::String : ItemKind::File;
+ const auto itemMimeType = QString::fromStdString(item["type"].as<std::string>());
+
+ switch (itemKind) {
+ case ItemKind::File: {
+ m_webFile = item.call<emscripten::val>("getAsFile");
+ qstdweb::File webfile(m_webFile);
+ QUrl fileUrl(QStringLiteral("file:///") + QString::fromStdString(webfile.name()));
+ uriList.append(fileUrl);
+ break;
+ }
+ case ItemKind::String:
+ if (itemMimeType.contains("STRING", Qt::CaseSensitive)
+ || itemMimeType.contains("TEXT", Qt::CaseSensitive)) {
+ break;
+ }
+ QString a;
+ QString data = QString::fromEcmaString(webDataTransfer.call<emscripten::val>(
+ "getData", emscripten::val(itemMimeType.toStdString())));
+
+ if (!data.isEmpty()) {
+ if (itemMimeType == "text/html")
+ resultMimeData->setHtml(data);
+ else if (itemMimeType.isEmpty() || itemMimeType == "text/plain")
+ resultMimeData->setText(data); // the type can be empty
+ else {
+ // TODO improve encoding
+ if (data.startsWith("QB64")) {
+ data.remove(0, 4);
+ resultMimeData->setData(itemMimeType,
+ QByteArray::fromBase64(QByteArray::fromStdString(
+ data.toStdString())));
+ } else {
+ resultMimeData->setData(itemMimeType, data.toLocal8Bit());
+ }
+ }
+ }
+ break;
+ }
+ }
+ if (!uriList.isEmpty())
+ resultMimeData->setUrls(uriList);
+ return resultMimeData;
+}
+
+QMimeData *DataTransfer::toMimeDataPreview()
+{
+ auto data = new QMimeData();
+
+ QList<QUrl> uriList;
+ for (int i = 0; i < webDataTransfer["items"]["length"].as<int>(); ++i) {
+ const auto item = webDataTransfer["items"][i];
+ if (item["kind"].as<std::string>() == "file") {
+ uriList.append(QUrl("blob://placeholder"));
+ } else {
+ const auto itemMimeType = QString::fromStdString(item["type"].as<std::string>());
+ data->setData(itemMimeType, QByteArray());
+ }
+ }
+ data->setUrls(uriList);
+ return data;
+}
void syncCSSClassWith(emscripten::val element, std::string cssClassName, bool flag)
{
diff --git a/src/plugins/platforms/wasm/qwasmdom.h b/src/plugins/platforms/wasm/qwasmdom.h
index 853e54540ec..3ccafba534c 100644
--- a/src/plugins/platforms/wasm/qwasmdom.h
+++ b/src/plugins/platforms/wasm/qwasmdom.h
@@ -6,6 +6,8 @@
#include <QtCore/qtconfigmacros.h>
#include <QtCore/QPointF>
+#include <private/qstdweb_p.h>
+#include <QtCore/qnamespace.h>
#include <emscripten/val.h>
@@ -15,10 +17,36 @@
QT_BEGIN_NAMESPACE
+namespace qstdweb {
+ struct CancellationFlag;
+}
+
+class QMimeData;
class QPoint;
class QRect;
namespace dom {
+struct DataTransfer
+{
+ explicit DataTransfer(emscripten::val webDataTransfer);
+ ~DataTransfer();
+ DataTransfer(const DataTransfer &other);
+ DataTransfer(DataTransfer &&other);
+ DataTransfer &operator=(const DataTransfer &other);
+ DataTransfer &operator=(DataTransfer &&other);
+
+ QMimeData *toMimeDataWithFile() ;
+ QMimeData *toMimeDataPreview();
+ void setDragImage(emscripten::val element, const QPoint &hotspot);
+ void setData(std::string format, std::string data);
+ void setDropAction(Qt::DropAction dropAction);
+ void setDataFromMimeData(const QMimeData &mimeData);
+
+ emscripten::val webDataTransfer;
+ emscripten::val m_webFile = emscripten::val::undefined();
+ qstdweb::File m_file;
+};
+
inline emscripten::val document()
{
return emscripten::val::global("document");
diff --git a/src/plugins/platforms/wasm/qwasmevent.h b/src/plugins/platforms/wasm/qwasmevent.h
index 8ccbbb71045..c5c20a0b5e9 100644
--- a/src/plugins/platforms/wasm/qwasmevent.h
+++ b/src/plugins/platforms/wasm/qwasmevent.h
@@ -5,6 +5,7 @@
#define QWASMEVENT_H
#include "qwasmplatform.h"
+#include "qwasmdom.h"
#include <QtCore/qglobal.h>
#include <QtCore/qnamespace.h>
@@ -241,7 +242,7 @@ struct DragEvent : public MouseEvent
void acceptDrop();
Qt::DropAction dropAction;
- emscripten::val dataTransfer;
+ dom::DataTransfer dataTransfer;
QWindow *targetWindow;
};
diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp
index bf2fdf47736..fa7eed14640 100644
--- a/src/plugins/platforms/wasm/qwasmwindow.cpp
+++ b/src/plugins/platforms/wasm/qwasmwindow.cpp
@@ -114,7 +114,6 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
std::make_unique<qstdweb::EventCallback>(m_qtWindow, "pointerenter", pointerCallback);
m_pointerLeaveCallback =
std::make_unique<qstdweb::EventCallback>(m_qtWindow, "pointerleave", pointerCallback);
-
m_dropCallback = std::make_unique<qstdweb::EventCallback>(
m_qtWindow, "drop", [this](emscripten::val event) {
if (processDrop(*DragEvent::fromWeb(event, window())))
@@ -538,25 +537,19 @@ bool QWasmWindow::processPointer(const PointerEvent &event)
bool QWasmWindow::processDrop(const DragEvent &event)
{
- m_dropDataReadCancellationFlag = qstdweb::readDataTransfer(
- event.dataTransfer,
- [](QByteArray fileContent) {
- QImage image;
- image.loadFromData(fileContent, nullptr);
- return image;
- },
- [this, event](std::unique_ptr<QMimeData> data) {
- QWindowSystemInterface::handleDrag(window(), data.get(),
- event.pointInPage.toPoint(), event.dropAction,
- event.mouseButton, event.modifiers);
-
- QWindowSystemInterface::handleDrop(window(), data.get(),
- event.pointInPage.toPoint(), event.dropAction,
- event.mouseButton, event.modifiers);
-
- QWindowSystemInterface::handleDrag(window(), nullptr, QPoint(), Qt::IgnoreAction,
- {}, {});
- });
+ dom::DataTransfer transfer(event.dataTransfer.webDataTransfer["clipboardData"]);
+ QMimeData *data = transfer.toMimeDataWithFile();
+ // TODO handle file
+ QWindowSystemInterface::handleDrag(window(), data,
+ event.pointInPage.toPoint(), event.dropAction,
+ event.mouseButton, event.modifiers);
+
+ QWindowSystemInterface::handleDrop(window(), data,
+ event.pointInPage.toPoint(), event.dropAction,
+ event.mouseButton, event.modifiers);
+
+ QWindowSystemInterface::handleDrag(window(), nullptr, QPoint(), Qt::IgnoreAction,
+ {}, {});
return true;
}