6#include <QtCore/qcoreapplication.h>
7#include <QtCore/qfile.h>
8#include <QtCore/qmimedata.h>
10#include <emscripten/bind.h>
11#include <emscripten/emscripten.h>
12#include <emscripten/html5.h>
13#include <emscripten/threading.h>
18#include <unordered_map>
35 volatile bool doIt =
false;
37 emscripten_set_wheel_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 0, NULL);
44struct ChunkedFileReader
48 std::function<
void()> onCompleted)
50 (
new ChunkedFileReader(
end, std::move(onCompleted), std::move(
file)))
55 ChunkedFileReader(uint32_t
end, std::function<
void()> onCompleted,
File file)
56 :
end(
end), onCompleted(std::move(onCompleted)),
file(std::move(
file))
60 void readNextChunk(uint32_t chunkBegin,
char *chunkBuffer)
67 const uint32_t nextChunkBegin = std::min(chunkBegin +
result.byteLength(),
end);
68 if (nextChunkBegin ==
end) {
73 char *nextChunkBuffer = chunkBuffer +
result.byteLength();
74 fileReader.
onLoad([
this, nextChunkBegin, nextChunkBuffer](emscripten::val) {
75 readNextChunk(nextChunkBegin, nextChunkBuffer);
77 const uint32_t nextChunkEnd = std::min(nextChunkBegin + chunkSize,
end);
82 static constexpr uint32_t chunkSize = 256 * 1024;
86 std::function<
void()> onCompleted;
90enum class CallbackType {
96void validateCallbacks(
const PromiseCallbacks&
callbacks) {
102#define THUNK_NAME(type, i) callbackThunk##type##i
117 class ThunkAllocation {
119 ThunkAllocation(
int thunkId, ThunkPool*
pool) : m_thunkId(thunkId), m_pool(
pool) {}
121 m_pool->free(m_thunkId);
125 int id()
const {
return m_thunkId; }
128 void bindToPromise(emscripten::val
target,
const PromiseCallbacks&
callbacks) {
134 emscripten::val::module_property(thunkName(CallbackType::Then,
id()).
data()));
139 emscripten::val::module_property(thunkName(CallbackType::Catch,
id()).
data()));
145 "finally", emscripten::val::module_property(
146 thunkName(CallbackType::Finally,
id()).
data()));
155 std::iota(m_free.begin(), m_free.end(), 0);
158 void setThunkCallback(std::function<
void(
int, CallbackType, emscripten::val)> callback) {
159 m_callback = std::move(callback);
162 void allocateThunk(std::function<
void(std::unique_ptr<ThunkAllocation>)> onAllocated) {
163 if (m_free.empty()) {
164 m_pendingAllocations.push_back(std::move(onAllocated));
168 const int thunkId = m_free.back();
170 onAllocated(std::make_unique<ThunkAllocation>(thunkId,
this));
176 case CallbackType::Then:
178 case CallbackType::Catch:
180 case CallbackType::Finally:
183 }()).arg(
i).toLatin1();
186 static ThunkPool*
get();
189 static void THUNK_NAME(Then, i)(emscripten::val result) \
191 get()->onThunkCalled(i, CallbackType::Then, std::move(result)); \
193 static void THUNK_NAME(Catch, i)(emscripten::val result) \
195 get()->onThunkCalled(i, CallbackType::Catch, std::move(result)); \
197 static void THUNK_NAME(Finally, i)() \
199 get()->onThunkCalled(i, CallbackType::Finally, emscripten::val::undefined()); \
210 void onThunkCalled(
int index, CallbackType
type, emscripten::val
result) {
214 void free(
int thunkId) {
215 if (m_pendingAllocations.empty()) {
217 m_free.push_back(thunkId);
222 auto allocation = m_pendingAllocations.back();
223 m_pendingAllocations.pop_back();
224 allocation(std::make_unique<ThunkAllocation>(thunkId,
this));
227 std::function<
void(
int, CallbackType, emscripten::val)> m_callback;
229 std::vector<int> m_free = std::vector<int>(poolSize);
230 std::vector<std::function<
void(std::unique_ptr<ThunkAllocation>)>> m_pendingAllocations;
235ThunkPool* ThunkPool::get()
240#define CALLBACK_BINDING(i) \
241 emscripten::function(ThunkPool::thunkName(CallbackType::Then, i).data(), \
242 &ThunkPool::THUNK_NAME(Then, i)); \
243 emscripten::function(ThunkPool::thunkName(CallbackType::Catch, i).data(), \
244 &ThunkPool::THUNK_NAME(Catch, i)); \
245 emscripten::function(ThunkPool::thunkName(CallbackType::Finally, i).data(), \
246 &ThunkPool::THUNK_NAME(Finally, i));
255#undef CALLBACK_BINDING
258class WebPromiseManager
262 ~WebPromiseManager();
264 WebPromiseManager(
const WebPromiseManager&
other) =
delete;
265 WebPromiseManager(WebPromiseManager&&
other) =
delete;
266 WebPromiseManager& operator=(
const WebPromiseManager&
other) =
delete;
267 WebPromiseManager& operator=(WebPromiseManager&&
other) =
delete;
271 static WebPromiseManager*
get();
274 struct RegistryEntry {
279 static std::optional<CallbackType> parseCallbackType(emscripten::val callbackType);
281 void subscribeToJsPromiseCallbacks(
int i,
const PromiseCallbacks&
callbacks, emscripten::val jsContextfulPromise);
282 void promiseThunkCallback(
int i, CallbackType
type, emscripten::val
result);
284 void registerPromise(std::unique_ptr<ThunkPool::ThunkAllocation>
allocation, PromiseCallbacks promise);
285 void unregisterPromise(ThunkId
context);
287 std::array<RegistryEntry, ThunkPool::poolSize> m_promiseRegistry;
292WebPromiseManager::WebPromiseManager()
294 ThunkPool::get()->setThunkCallback(std::bind(
295 &WebPromiseManager::promiseThunkCallback,
this,
296 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
299std::optional<CallbackType>
300WebPromiseManager::parseCallbackType(emscripten::val callbackType)
302 if (!callbackType.isString())
305 const std::string
data = callbackType.as<std::string>();
307 return CallbackType::Then;
309 return CallbackType::Catch;
310 if (
data ==
"finally")
311 return CallbackType::Finally;
315WebPromiseManager::~WebPromiseManager() =
default;
317WebPromiseManager *WebPromiseManager::get()
319 return webPromiseManager();
322void WebPromiseManager::promiseThunkCallback(
int context, CallbackType
type, emscripten::val
result)
324 auto* promiseState = &m_promiseRegistry[
context];
326 auto*
callbacks = &promiseState->callbacks;
328 case CallbackType::Then:
331 case CallbackType::Catch:
334 case CallbackType::Finally:
344void WebPromiseManager::registerPromise(
345 std::unique_ptr<ThunkPool::ThunkAllocation>
allocation,
349 m_promiseRegistry[
id] =
353void WebPromiseManager::unregisterPromise(ThunkId
context)
355 m_promiseRegistry[
context] = {};
358void WebPromiseManager::adoptPromise(emscripten::val
target, PromiseCallbacks
callbacks) {
359 ThunkPool::get()->allocateThunk([=](std::unique_ptr<ThunkPool::ThunkAllocation>
allocation) {
364#if defined(QT_STATIC)
366EM_JS(
bool, jsHaveAsyncify, (), {
return typeof Asyncify !==
"undefined"; });
367EM_JS(
bool, jsHaveJspi, (),
368 {
return typeof Asyncify !==
"undefined" && !!Asyncify.makeAsyncFunction && !!WebAssembly.Function; });
372bool jsHaveAsyncify() {
return false; }
373bool jsHaveJspi() {
return false; }
380 m_arrayBuffer = emscripten::val::global(
"ArrayBuffer").new_(
size);
384 :m_arrayBuffer(arrayBuffer)
391 if (m_arrayBuffer.isUndefined() || m_arrayBuffer.isNull())
394 return m_arrayBuffer[
"byteLength"].as<uint32_t>();
404 return m_arrayBuffer;
415 auto array = emscripten::val::array();
416 array.call<
void>(
"push", arrayBuffer.val());
417 return Blob(emscripten::val::global(
"Blob").new_(
array));
422 return m_blob[
"size"].as<uint32_t>();
429 emscripten::val contentArray = emscripten::val::array();
430 contentArray.call<
void>(
"push", contentCopy.val());
431 emscripten::val
type = emscripten::val::object();
433 return Blob(emscripten::val::global(
"Blob").new_(contentArray,
type));
444 return Blob(m_blob.call<emscripten::val>(
"slice",
begin,
end));
452 .thenFunc = [&loop, &
buffer](emscripten::val arrayBuffer) {
466File::File(
const emscripten::val &
file)
472File::~File() =
default;
488std::string File::name()
const
490 return m_file[
"name"].as<std::string>();
493uint64_t File::size()
const
495 return uint64_t(m_file[
"size"].as<uint53_t>());
500 return m_blob[
"type"].as<std::string>();
506 std::function<
void()> completed)
const
513void File::stream(
char *
buffer, std::function<
void()> completed)
const
518std::string File::type()
const
520 return m_file[
"type"].as<std::string>();
523emscripten::val File::val()
const
531 "createObjectURL",
file.file()));
536 emscripten::val::global(
"window")[
"URL"].call<
void>(
"revokeObjectURL",
545 :m_fileList(fileList)
552 return m_fileList[
"length"].as<
int>();
577 m_fileReader.call<
void>(
"readAsArrayBuffer", blob.m_blob);
583 m_onLoad = std::make_unique<EventCallback>(m_fileReader,
"load",
onLoad);
589 m_onError = std::make_unique<EventCallback>(m_fileReader,
"error",
onError);
595 m_onAbort = std::make_unique<EventCallback>(m_fileReader,
"abort",
onAbort);
610: m_uint8Array(uint8Array)
650 return m_uint8Array[
"length"].as<uint32_t>();
655 m_uint8Array.call<
void>(
"set",
source.m_uint8Array);
674 if (
length() > std::numeric_limits<qsizetype>::max())
679 copyTo(destinationArray.data());
680 return destinationArray;
708emscripten::val Uint8Array::heap_()
710 return emscripten::val::module_property(
"HEAPU8");
713emscripten::val Uint8Array::constructor_()
715 return emscripten::val::global(
"Uint8Array");
729 auto handlerPtr =
reinterpret_cast<std::function<
void(emscripten::val)
> *>(
m_handler);
730 (*handlerPtr)(
event);
740 m_element.call<
void>(
"removeEventListener", m_eventName, m_eventListener);
748 uintptr_t handlerUint =
reinterpret_cast<uintptr_t
>(m_handler.get());
749 m_eventListener = emscripten::val::module_property(
"QtEventListener").new_(handlerUint);
750 m_element.call<
void>(
"addEventListener", m_eventName, m_eventListener);
754 emscripten::class_<EventListener>(
"QtEventListener")
755 .constructor<uintptr_t>()
763 WebPromiseManager::get()->adoptPromise(
764 std::move(promiseObject), std::move(
callbacks));
769 std::map<int, emscripten::val>
results;
770 int remainingThenCallbacks;
771 int remainingFinallyCallbacks;
776 auto state = std::make_shared<State>();
777 state->remainingThenCallbacks =
state->remainingFinallyCallbacks = promises.size();
779 for (
size_t i = 0;
i < promises.size(); ++
i) {
783 state->results.emplace(
i, std::move(partialResult));
784 if (!--(
state->remainingThenCallbacks)) {
785 std::vector<emscripten::val> transformed;
787 transformed.push_back(std::move(
data.second));
789 callbacks.thenFunc(emscripten::val::array(std::move(transformed)));
798 individualPromiseCallback.finallyFunc = [
state,
callbacks]()
mutable {
799 if (!--(
state->remainingFinallyCallbacks)) {
808 adoptPromise(std::move(promises.at(
i)), std::move(individualPromiseCallback));
825 static bool HaveJspi = jsHaveJspi();
831 static bool HaveAsyncify = jsHaveAsyncify() ||
haveJspi();
837 return haveAsyncify() || !emscripten_is_main_runtime_thread();
860 return m_blob.
size();
873 uint64_t
end = std::min<uint64_t>(
begin + maxSize,
size());
918 uint64_t
end = std::min<uint64_t>(
begin + maxSize,
size());
928 uint64_t
end = std::min<uint64_t>(
begin + maxSize,
size());
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
int exec(ProcessEventsFlags flags=AllEvents)
Enters the main event loop and waits until exit() is called.
void quit()
Tells the event loop to exit normally.
virtual bool open(QIODeviceBase::OpenMode mode)
Opens the device and sets its OpenMode to mode.
virtual qint64 pos() const
For random-access devices, this function returns the position that data is written to or read from.
virtual bool seek(qint64 pos)
For random-access devices, this function sets the current position to pos, returning true on success,...
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromStdString(const std::string &s)
std::string toStdString() const
Returns a std::string object with the data contained in this QString.
ArrayBuffer slice(uint32_t begin, uint32_t end) const
emscripten::val val() const
uint32_t byteLength() const
ArrayBuffer(uint32_t size)
bool seek(qint64 pos) override
For random-access devices, this function sets the current position to pos, returning true on success,...
bool isSequential() const override
Returns true if this device is sequential; otherwise returns false.
qint64 writeData(const char *, qint64) override
Writes up to maxSize bytes from data to the device.
qint64 size() const override
For open random-access devices, this function returns the size of the device.
bool open(QIODeviceBase::OpenMode mode) override
Opens the device and sets its OpenMode to mode.
qint64 readData(char *data, qint64 maxSize) override
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
Blob slice(uint32_t begin, uint32_t end) const
ArrayBuffer arrayBuffer_sync() const
Blob(const emscripten::val &blob)
static Blob copyFrom(const char *buffer, uint32_t size, std::string mimeType)
emscripten::val val() const
static Blob fromArrayBuffer(const ArrayBuffer &arrayBuffer)
void handleEvent(emscripten::val event)
EventListener(uintptr_t handler)
File item(int index) const
emscripten::val val() const
File operator[](int index) const
void onAbort(const std::function< void(emscripten::val)> &onAbort)
ArrayBuffer result() const
void onLoad(const std::function< void(emscripten::val)> &onLoad)
void readAsArrayBuffer(const Blob &blob) const
void onError(const std::function< void(emscripten::val)> &onError)
emscripten::val val() const
FileUrlRegistration(File file)
FileUrlRegistration & operator=(const FileUrlRegistration &other)=delete
qint64 size() const override
For open random-access devices, this function returns the size of the device.
bool seek(qint64 pos) override
For random-access devices, this function sets the current position to pos, returning true on success,...
Uint8ArrayIODevice(Uint8Array array)
bool isSequential() const override
Returns true if this device is sequential; otherwise returns false.
qint64 writeData(const char *data, qint64 size) override
Writes up to maxSize bytes from data to the device.
bool open(QIODevice::OpenMode mode) override
qint64 readData(char *data, qint64 maxSize) override
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
emscripten::val val() const
void copyTo(char *destination) const
Uint8Array subarray(uint32_t begin, uint32_t end)
void set(const Uint8Array &source)
ArrayBuffer buffer() const
QByteArray copyToQByteArray() const
Uint8Array(const emscripten::val &uint8Array)
static Uint8Array copyFrom(const char *buffer, uint32_t size)
static void copy(char *destination, const Uint8Array &source)
Combined button and popup list for selecting options.
void make(emscripten::val target, QString methodName, PromiseCallbacks callbacks, Args... args)
void adoptPromise(emscripten::val promiseObject, PromiseCallbacks callbacks)
void all(std::vector< emscripten::val > promises, PromiseCallbacks callbacks)
bool canBlockCallingThread()
static void usePotentialyUnusedSymbols()
EMSCRIPTEN_BINDINGS(qtStdwebCalback)
Q_CONSTRUCTOR_FUNCTION(qt_apple_check_os_version)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char * destination
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError * error
static QDBusError::ErrorType get(const char *name)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLsizei GLsizei GLchar * source
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
std::unique_ptr< ThunkPool::ThunkAllocation > allocation
PromiseCallbacks callbacks
static constexpr size_t poolSize
#define CALLBACK_BINDING(i)
#define QStringLiteral(str)
decltype(openFileForWriting({})) File
ReturnedValue read(const char *data)
std::function< void(emscripten::val)> thenFunc
std::function< void()> finallyFunc
std::function< void(emscripten::val)> catchFunc