Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qstdweb.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qstdweb_p.h"
5
6#include <QtCore/qcoreapplication.h>
7#include <QtCore/qfile.h>
8#include <QtCore/qmimedata.h>
9
10#include <emscripten/bind.h>
11#include <emscripten/emscripten.h>
12#include <emscripten/html5.h>
13#include <emscripten/threading.h>
14
15#include <cstdint>
16#include <iostream>
17
18#include <unordered_map>
19
21
22using namespace Qt::Literals::StringLiterals;
23
24namespace qstdweb {
25
27{
28 // Using this adds a reference on JSEvents and specialHTMLTargets which are always exported.
29 // This hack is needed as it is currently impossible to specify a dollar sign in
30 // target_link_options. The following is impossible:
31 // DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$JSEvents
32 // TODO(mikolajboc): QTBUG-108444, review this when cmake gets fixed.
33 // Volatile is to make this unoptimizable, so that the function is referenced, but is not
34 // called at runtime.
35 volatile bool doIt = false;
36 if (doIt)
37 emscripten_set_wheel_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 0, NULL);
38}
39
41typedef double uint53_t; // see Number.MAX_SAFE_INTEGER
42namespace {
43// Reads file in chunks in order to avoid holding two copies in memory at the same time
44struct ChunkedFileReader
45{
46public:
47 static void read(File file, char *buffer, uint32_t offset, uint32_t end,
48 std::function<void()> onCompleted)
49 {
50 (new ChunkedFileReader(end, std::move(onCompleted), std::move(file)))
51 ->readNextChunk(offset, buffer);
52 }
53
54private:
55 ChunkedFileReader(uint32_t end, std::function<void()> onCompleted, File file)
56 : end(end), onCompleted(std::move(onCompleted)), file(std::move(file))
57 {
58 }
59
60 void readNextChunk(uint32_t chunkBegin, char *chunkBuffer)
61 {
62 // Copy current chunk from JS memory to Wasm memory
63 qstdweb::ArrayBuffer result = fileReader.result();
64 qstdweb::Uint8Array(result).copyTo(chunkBuffer);
65
66 // Read next chunk if not at buffer end
67 const uint32_t nextChunkBegin = std::min(chunkBegin + result.byteLength(), end);
68 if (nextChunkBegin == end) {
69 onCompleted();
70 delete this;
71 return;
72 }
73 char *nextChunkBuffer = chunkBuffer + result.byteLength();
74 fileReader.onLoad([this, nextChunkBegin, nextChunkBuffer](emscripten::val) {
75 readNextChunk(nextChunkBegin, nextChunkBuffer);
76 });
77 const uint32_t nextChunkEnd = std::min(nextChunkBegin + chunkSize, end);
78 qstdweb::Blob blob = file.slice(nextChunkBegin, nextChunkEnd);
79 fileReader.readAsArrayBuffer(blob);
80 }
81
82 static constexpr uint32_t chunkSize = 256 * 1024;
83
84 qstdweb::FileReader fileReader;
85 uint32_t end;
86 std::function<void()> onCompleted;
87 File file;
88};
89
90enum class CallbackType {
91 Then,
92 Catch,
93 Finally,
94};
95
96void validateCallbacks(const PromiseCallbacks& callbacks) {
98}
99
100using ThunkId = int;
101
102#define THUNK_NAME(type, i) callbackThunk##type##i
103
104// A resource pool for exported promise thunk functions. ThunkPool::poolSize sets of
105// 3 promise thunks (then, catch, finally) are exported and can be used by promises
106// in C++. To allocate a thunk, call allocateThunk. When a thunk is ready for use,
107// a callback with allocation RAII object ThunkAllocation will be returned. Deleting
108// the object frees the thunk and automatically makes any pending allocateThunk call
109// run its callback with a free thunk slot.
110class ThunkPool {
111public:
112 static constexpr size_t poolSize = 4;
113
114 // An allocation for a thunk function set. Following the RAII pattern, destruction of
115 // this objects frees a corresponding thunk pool entry.
116 // To actually make the thunks react to a js promise's callbacks, call bindToPromise.
117 class ThunkAllocation {
118 public:
119 ThunkAllocation(int thunkId, ThunkPool* pool) : m_thunkId(thunkId), m_pool(pool) {}
120 ~ThunkAllocation() {
121 m_pool->free(m_thunkId);
122 }
123
124 // The id of the underlaying thunk set
125 int id() const { return m_thunkId; }
126
127 // Binds the corresponding thunk set to the js promise 'target'.
128 void bindToPromise(emscripten::val target, const PromiseCallbacks& callbacks) {
129 using namespace emscripten;
130
131 if (Q_LIKELY(callbacks.thenFunc)) {
132 target = target.call<val>(
133 "then",
134 emscripten::val::module_property(thunkName(CallbackType::Then, id()).data()));
135 }
136 if (callbacks.catchFunc) {
137 target = target.call<val>(
138 "catch",
139 emscripten::val::module_property(thunkName(CallbackType::Catch, id()).data()));
140 }
141 // Guarantee the invocation of at least one callback by always
142 // registering 'finally'. This is required by WebPromiseManager
143 // design
144 target = target.call<val>(
145 "finally", emscripten::val::module_property(
146 thunkName(CallbackType::Finally, id()).data()));
147 }
148
149 private:
150 int m_thunkId;
151 ThunkPool* m_pool;
152 };
153
154 ThunkPool() {
155 std::iota(m_free.begin(), m_free.end(), 0);
156 }
157
158 void setThunkCallback(std::function<void(int, CallbackType, emscripten::val)> callback) {
159 m_callback = std::move(callback);
160 }
161
162 void allocateThunk(std::function<void(std::unique_ptr<ThunkAllocation>)> onAllocated) {
163 if (m_free.empty()) {
164 m_pendingAllocations.push_back(std::move(onAllocated));
165 return;
166 }
167
168 const int thunkId = m_free.back();
169 m_free.pop_back();
170 onAllocated(std::make_unique<ThunkAllocation>(thunkId, this));
171 }
172
173 static QByteArray thunkName(CallbackType type, size_t i) {
174 return QStringLiteral("promiseCallback%1%2").arg([type]() -> QString {
175 switch (type) {
176 case CallbackType::Then:
177 return QStringLiteral("Then");
178 case CallbackType::Catch:
179 return QStringLiteral("Catch");
180 case CallbackType::Finally:
181 return QStringLiteral("Finally");
182 }
183 }()).arg(i).toLatin1();
184 }
185
186 static ThunkPool* get();
187
188#define THUNK(i) \
189 static void THUNK_NAME(Then, i)(emscripten::val result) \
190 { \
191 get()->onThunkCalled(i, CallbackType::Then, std::move(result)); \
192 } \
193 static void THUNK_NAME(Catch, i)(emscripten::val result) \
194 { \
195 get()->onThunkCalled(i, CallbackType::Catch, std::move(result)); \
196 } \
197 static void THUNK_NAME(Finally, i)() \
198 { \
199 get()->onThunkCalled(i, CallbackType::Finally, emscripten::val::undefined()); \
200 }
201
202 THUNK(0);
203 THUNK(1);
204 THUNK(2);
205 THUNK(3);
206
207#undef THUNK
208
209private:
210 void onThunkCalled(int index, CallbackType type, emscripten::val result) {
211 m_callback(index, type, std::move(result));
212 }
213
214 void free(int thunkId) {
215 if (m_pendingAllocations.empty()) {
216 // Return the thunk to the free pool
217 m_free.push_back(thunkId);
218 return;
219 }
220
221 // Take the next enqueued allocation and reuse the thunk
222 auto allocation = m_pendingAllocations.back();
223 m_pendingAllocations.pop_back();
224 allocation(std::make_unique<ThunkAllocation>(thunkId, this));
225 }
226
227 std::function<void(int, CallbackType, emscripten::val)> m_callback;
228
229 std::vector<int> m_free = std::vector<int>(poolSize);
230 std::vector<std::function<void(std::unique_ptr<ThunkAllocation>)>> m_pendingAllocations;
231};
232
233Q_GLOBAL_STATIC(ThunkPool, g_thunkPool)
234
235ThunkPool* ThunkPool::get()
236{
237 return g_thunkPool;
238}
239
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));
247
248EMSCRIPTEN_BINDINGS(qtThunkPool) {
253}
254
255#undef CALLBACK_BINDING
256#undef THUNK_NAME
257
258class WebPromiseManager
259{
260public:
261 WebPromiseManager();
262 ~WebPromiseManager();
263
264 WebPromiseManager(const WebPromiseManager& other) = delete;
265 WebPromiseManager(WebPromiseManager&& other) = delete;
266 WebPromiseManager& operator=(const WebPromiseManager& other) = delete;
267 WebPromiseManager& operator=(WebPromiseManager&& other) = delete;
268
269 void adoptPromise(emscripten::val target, PromiseCallbacks callbacks);
270
271 static WebPromiseManager* get();
272
273private:
274 struct RegistryEntry {
275 PromiseCallbacks callbacks;
276 std::unique_ptr<ThunkPool::ThunkAllocation> allocation;
277 };
278
279 static std::optional<CallbackType> parseCallbackType(emscripten::val callbackType);
280
281 void subscribeToJsPromiseCallbacks(int i, const PromiseCallbacks& callbacks, emscripten::val jsContextfulPromise);
282 void promiseThunkCallback(int i, CallbackType type, emscripten::val result);
283
284 void registerPromise(std::unique_ptr<ThunkPool::ThunkAllocation> allocation, PromiseCallbacks promise);
285 void unregisterPromise(ThunkId context);
286
287 std::array<RegistryEntry, ThunkPool::poolSize> m_promiseRegistry;
288};
289
290Q_GLOBAL_STATIC(WebPromiseManager, webPromiseManager)
291
292WebPromiseManager::WebPromiseManager()
293{
294 ThunkPool::get()->setThunkCallback(std::bind(
295 &WebPromiseManager::promiseThunkCallback, this,
296 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
297}
298
299std::optional<CallbackType>
300WebPromiseManager::parseCallbackType(emscripten::val callbackType)
301{
302 if (!callbackType.isString())
303 return std::nullopt;
304
305 const std::string data = callbackType.as<std::string>();
306 if (data == "then")
307 return CallbackType::Then;
308 if (data == "catch")
309 return CallbackType::Catch;
310 if (data == "finally")
311 return CallbackType::Finally;
312 return std::nullopt;
313}
314
315WebPromiseManager::~WebPromiseManager() = default;
316
317WebPromiseManager *WebPromiseManager::get()
318{
319 return webPromiseManager();
320}
321
322void WebPromiseManager::promiseThunkCallback(int context, CallbackType type, emscripten::val result)
323{
324 auto* promiseState = &m_promiseRegistry[context];
325
326 auto* callbacks = &promiseState->callbacks;
327 switch (type) {
328 case CallbackType::Then:
329 callbacks->thenFunc(result);
330 break;
331 case CallbackType::Catch:
332 callbacks->catchFunc(result);
333 break;
334 case CallbackType::Finally:
335 // Final callback may be empty, used solely for promise unregistration
336 if (callbacks->finallyFunc) {
337 callbacks->finallyFunc();
338 }
339 unregisterPromise(context);
340 break;
341 }
342}
343
344void WebPromiseManager::registerPromise(
345 std::unique_ptr<ThunkPool::ThunkAllocation> allocation,
346 PromiseCallbacks callbacks)
347{
348 const ThunkId id = allocation->id();
349 m_promiseRegistry[id] =
350 RegistryEntry {std::move(callbacks), std::move(allocation)};
351}
352
353void WebPromiseManager::unregisterPromise(ThunkId context)
354{
355 m_promiseRegistry[context] = {};
356}
357
358void WebPromiseManager::adoptPromise(emscripten::val target, PromiseCallbacks callbacks) {
359 ThunkPool::get()->allocateThunk([=](std::unique_ptr<ThunkPool::ThunkAllocation> allocation) {
360 allocation->bindToPromise(std::move(target), callbacks);
361 registerPromise(std::move(allocation), std::move(callbacks));
362 });
363}
364#if defined(QT_STATIC)
365
366EM_JS(bool, jsHaveAsyncify, (), { return typeof Asyncify !== "undefined"; });
367EM_JS(bool, jsHaveJspi, (),
368 { return typeof Asyncify !== "undefined" && !!Asyncify.makeAsyncFunction && !!WebAssembly.Function; });
369
370#else
371
372bool jsHaveAsyncify() { return false; }
373bool jsHaveJspi() { return false; }
374
375#endif
376} // namespace
377
379{
380 m_arrayBuffer = emscripten::val::global("ArrayBuffer").new_(size);
381}
382
383ArrayBuffer::ArrayBuffer(const emscripten::val &arrayBuffer)
384 :m_arrayBuffer(arrayBuffer)
385{
386
387}
388
390{
391 if (m_arrayBuffer.isUndefined() || m_arrayBuffer.isNull())
392 return 0;
393
394 return m_arrayBuffer["byteLength"].as<uint32_t>();
395}
396
397ArrayBuffer ArrayBuffer::slice(uint32_t begin, uint32_t end) const
398{
399 return ArrayBuffer(m_arrayBuffer.call<emscripten::val>("slice", begin, end));
400}
401
402emscripten::val ArrayBuffer::val() const
403{
404 return m_arrayBuffer;
405}
406
407Blob::Blob(const emscripten::val &blob)
408 :m_blob(blob)
409{
410
411}
412
414{
415 auto array = emscripten::val::array();
416 array.call<void>("push", arrayBuffer.val());
417 return Blob(emscripten::val::global("Blob").new_(array));
418}
419
420uint32_t Blob::size() const
421{
422 return m_blob["size"].as<uint32_t>();
423}
424
425Blob Blob::copyFrom(const char *buffer, uint32_t size, std::string mimeType)
426{
428
429 emscripten::val contentArray = emscripten::val::array();
430 contentArray.call<void>("push", contentCopy.val());
431 emscripten::val type = emscripten::val::object();
432 type.set("type", std::move(mimeType));
433 return Blob(emscripten::val::global("Blob").new_(contentArray, type));
434}
435
436// Copies content from the given buffer into a Blob object
437Blob Blob::copyFrom(const char *buffer, uint32_t size)
438{
439 return copyFrom(buffer, size, "application/octet-stream");
440}
441
442Blob Blob::slice(uint32_t begin, uint32_t end) const
443{
444 return Blob(m_blob.call<emscripten::val>("slice", begin, end));
445}
446
448{
449 QEventLoop loop;
450 emscripten::val buffer;
451 qstdweb::Promise::make(m_blob, QStringLiteral("arrayBuffer"), {
452 .thenFunc = [&loop, &buffer](emscripten::val arrayBuffer) {
453 buffer = arrayBuffer;
454 loop.quit();
455 }
456 });
457 loop.exec();
458 return ArrayBuffer(buffer);
459}
460
461emscripten::val Blob::val() const
462{
463 return m_blob;
464}
465
466File::File(const emscripten::val &file)
467:m_file(file)
468{
469
470}
471
472File::~File() = default;
473
474File::File(const File &other) = default;
475
476File::File(File &&other) = default;
477
478File &File::operator=(const File &other) = default;
479
480File &File::operator=(File &&other) = default;
481
482
483Blob File::slice(uint64_t begin, uint64_t end) const
484{
485 return Blob(m_file.call<emscripten::val>("slice", uint53_t(begin), uint53_t(end)));
486}
487
488std::string File::name() const
489{
490 return m_file["name"].as<std::string>();
491}
492
493uint64_t File::size() const
494{
495 return uint64_t(m_file["size"].as<uint53_t>());
496}
497
498std::string Blob::type() const
499{
500 return m_blob["type"].as<std::string>();
501}
502
503// Streams partial file content into the given buffer asynchronously. The completed
504// callback is called on completion.
505void File::stream(uint32_t offset, uint32_t length, char *buffer,
506 std::function<void()> completed) const
507{
508 ChunkedFileReader::read(*this, buffer, offset, offset + length, std::move(completed));
509}
510
511// Streams file content into the given buffer asynchronously. The completed
512// callback is called on completion.
513void File::stream(char *buffer, std::function<void()> completed) const
514{
515 stream(0, size(), buffer, std::move(completed));
516}
517
518std::string File::type() const
519{
520 return m_file["type"].as<std::string>();
521}
522
523emscripten::val File::val() const
524{
525 return m_file;
526}
527
529{
530 m_path = QString::fromStdString(emscripten::val::global("window")["URL"].call<std::string>(
531 "createObjectURL", file.file()));
532}
533
535{
536 emscripten::val::global("window")["URL"].call<void>("revokeObjectURL",
537 emscripten::val(m_path.toStdString()));
538}
539
541
543
544FileList::FileList(const emscripten::val &fileList)
545 :m_fileList(fileList)
546{
547
548}
549
551{
552 return m_fileList["length"].as<int>();
553}
554
556{
557 return File(m_fileList[index]);
558}
559
561{
562 return item(index);
563}
564
565emscripten::val FileList::val() const
566{
567 return m_fileList;
568}
569
571{
572 return ArrayBuffer(m_fileReader["result"]);
573}
574
575void FileReader::readAsArrayBuffer(const Blob &blob) const
576{
577 m_fileReader.call<void>("readAsArrayBuffer", blob.m_blob);
578}
579
580void FileReader::onLoad(const std::function<void(emscripten::val)> &onLoad)
581{
582 m_onLoad.reset();
583 m_onLoad = std::make_unique<EventCallback>(m_fileReader, "load", onLoad);
584}
585
586void FileReader::onError(const std::function<void(emscripten::val)> &onError)
587{
588 m_onError.reset();
589 m_onError = std::make_unique<EventCallback>(m_fileReader, "error", onError);
590}
591
592void FileReader::onAbort(const std::function<void(emscripten::val)> &onAbort)
593{
594 m_onAbort.reset();
595 m_onAbort = std::make_unique<EventCallback>(m_fileReader, "abort", onAbort);
596}
597
598emscripten::val FileReader::val() const
599{
600 return m_fileReader;
601}
602
604{
605 return Uint8Array(heap_());
606}
607
608// Constructs a Uint8Array which references the given emscripten::val, which must contain a JS Unit8Array
609Uint8Array::Uint8Array(const emscripten::val &uint8Array)
610: m_uint8Array(uint8Array)
611{
612
613}
614
615// Constructs a Uint8Array which references an ArrayBuffer
617: m_uint8Array(Uint8Array::constructor_().new_(buffer.m_arrayBuffer))
618{
619
620}
621
622// Constructs a Uint8Array which references a view into an ArrayBuffer
624: m_uint8Array(Uint8Array::constructor_().new_(buffer.m_arrayBuffer, offset, length))
625{
626
627}
628
629// Constructs a Uint8Array which references an area on the heap.
630Uint8Array::Uint8Array(const char *buffer, uint32_t size)
631:m_uint8Array(Uint8Array::constructor_().new_(Uint8Array::heap().buffer().m_arrayBuffer, uintptr_t(buffer), size))
632{
633
634}
635
636// Constructs a Uint8Array which allocates and references a new ArrayBuffer with the given size.
638: m_uint8Array(Uint8Array::constructor_().new_(size))
639{
640
641}
642
644{
645 return ArrayBuffer(m_uint8Array["buffer"]);
646}
647
648uint32_t Uint8Array::length() const
649{
650 return m_uint8Array["length"].as<uint32_t>();
651}
652
654{
655 m_uint8Array.call<void>("set", source.m_uint8Array); // copies source content
656}
657
659{
660 // Note: using uint64_t here errors with "Cannot convert a BigInt value to a number"
661 // (see JS BigInt and Number types). Use uint32_t for now.
662 return Uint8Array(m_uint8Array.call<emscripten::val>("subarray", begin, end));
663}
664
665// Copies the Uint8Array content to a destination on the heap
667{
668 Uint8Array(destination, length()).set(*this);
669}
670
671// Copies the Uint8Array content to a destination QByteArray
673{
674 if (length() > std::numeric_limits<qsizetype>::max())
675 return QByteArray();
676
677 QByteArray destinationArray;
678 destinationArray.resize(length());
679 copyTo(destinationArray.data());
680 return destinationArray;
681}
682
683// Copies the Uint8Array content to a destination on the heap
685{
686 Uint8Array(destination, source.length()).set(source);
687}
688
689// Copies content from a source on the heap to a new Uint8Array object
691{
692 Uint8Array contentCopy(size);
693 contentCopy.set(Uint8Array(buffer, size));
694 return contentCopy;
695}
696
697// Copies content from a QByteArray to a new Uint8Array object
699{
700 return copyFrom(buffer.constData(), buffer.size());
701}
702
703emscripten::val Uint8Array::val() const
704{
705 return m_uint8Array;
706}
707
708emscripten::val Uint8Array::heap_()
709{
710 return emscripten::val::module_property("HEAPU8");
711}
712
713emscripten::val Uint8Array::constructor_()
714{
715 return emscripten::val::global("Uint8Array");
716}
717
719public:
720 EventListener(uintptr_t handler)
721 :m_handler(handler)
722 {
723
724 }
725
726 // Special function - addEventListender() allows adding an object with a
727 // handleEvent() function which eceives the event.
728 void handleEvent(emscripten::val event) {
729 auto handlerPtr = reinterpret_cast<std::function<void(emscripten::val)> *>(m_handler);
730 (*handlerPtr)(event);
731 }
732
733 uintptr_t m_handler;
734};
735
736// Registers a callback function for a named event on the given element. The event
737// name must be the name as returned by the Event.type property: e.g. "load", "error".
739{
740 m_element.call<void>("removeEventListener", m_eventName, m_eventListener);
741}
742
743EventCallback::EventCallback(emscripten::val element, const std::string &name, const std::function<void(emscripten::val)> &handler)
744 :m_element(element)
745 ,m_eventName(name)
746 ,m_handler(std::make_unique<std::function<void(emscripten::val)>>(handler))
747{
748 uintptr_t handlerUint = reinterpret_cast<uintptr_t>(m_handler.get()); // FIXME: pass pointer directly instead
749 m_eventListener = emscripten::val::module_property("QtEventListener").new_(handlerUint);
750 m_element.call<void>("addEventListener", m_eventName, m_eventListener);
751}
752
753EMSCRIPTEN_BINDINGS(qtStdwebCalback) {
754 emscripten::class_<EventListener>("QtEventListener")
755 .constructor<uintptr_t>()
756 .function("handleEvent", &EventListener::handleEvent);
757}
758
759namespace Promise {
760 void adoptPromise(emscripten::val promiseObject, PromiseCallbacks callbacks) {
761 validateCallbacks(callbacks);
762
763 WebPromiseManager::get()->adoptPromise(
764 std::move(promiseObject), std::move(callbacks));
765 }
766
767 void all(std::vector<emscripten::val> promises, PromiseCallbacks callbacks) {
768 struct State {
769 std::map<int, emscripten::val> results;
770 int remainingThenCallbacks;
771 int remainingFinallyCallbacks;
772 };
773
774 validateCallbacks(callbacks);
775
776 auto state = std::make_shared<State>();
777 state->remainingThenCallbacks = state->remainingFinallyCallbacks = promises.size();
778
779 for (size_t i = 0; i < promises.size(); ++i) {
780 PromiseCallbacks individualPromiseCallback;
781 if (callbacks.thenFunc) {
782 individualPromiseCallback.thenFunc = [i, state, callbacks](emscripten::val partialResult) mutable {
783 state->results.emplace(i, std::move(partialResult));
784 if (!--(state->remainingThenCallbacks)) {
785 std::vector<emscripten::val> transformed;
786 for (auto& data : state->results) {
787 transformed.push_back(std::move(data.second));
788 }
789 callbacks.thenFunc(emscripten::val::array(std::move(transformed)));
790 }
791 };
792 }
793 if (callbacks.catchFunc) {
794 individualPromiseCallback.catchFunc = [state, callbacks](emscripten::val error) mutable {
795 callbacks.catchFunc(error);
796 };
797 }
798 individualPromiseCallback.finallyFunc = [state, callbacks]() mutable {
799 if (!--(state->remainingFinallyCallbacks)) {
800 if (callbacks.finallyFunc)
801 callbacks.finallyFunc();
802 // Explicitly reset here for verbosity, this would have been done automatically with the
803 // destruction of the adopted promise in WebPromiseManager.
804 state.reset();
805 }
806 };
807
808 adoptPromise(std::move(promises.at(i)), std::move(individualPromiseCallback));
809 }
810 }
811}
812
813// Asyncify and thread blocking: Normally, it's not possible to block the main
814// thread, except if asyncify is enabled. Secondary threads can always block.
815//
816// haveAsyncify(): returns true if the main thread can block on QEventLoop::exec(),
817// if either asyncify 1 or 2 (JSPI) is available.
818//
819// haveJspi(): returns true if asyncify 2 (JSPI) is available.
820//
821// canBlockCallingThread(): returns true if the calling thread can block on
822// QEventLoop::exec(), using either asyncify or as a seconarday thread.
824{
825 static bool HaveJspi = jsHaveJspi();
826 return HaveJspi;
827}
828
830{
831 static bool HaveAsyncify = jsHaveAsyncify() || haveJspi();
832 return HaveAsyncify;
833}
834
836{
837 return haveAsyncify() || !emscripten_is_main_runtime_thread();
838}
839
841 : m_blob(blob)
842{
843
844}
845
846bool BlobIODevice::open(QIODevice::OpenMode mode)
847{
848 if (mode.testFlag(QIODevice::WriteOnly))
849 return false;
850 return QIODevice::open(mode);
851}
852
854{
855 return false;
856}
857
859{
860 return m_blob.size();
861}
862
864{
865 if (pos >= size())
866 return false;
867 return QIODevice::seek(pos);
868}
869
871{
872 uint64_t begin = QIODevice::pos();
873 uint64_t end = std::min<uint64_t>(begin + maxSize, size());
874 uint64_t size = end - begin;
875 if (size > 0) {
878 }
879 return size;
880}
881
883{
884 Q_UNREACHABLE();
885}
886
892
893bool Uint8ArrayIODevice::open(QIODevice::OpenMode mode)
894{
895 return QIODevice::open(mode);
896}
897
899{
900 return false;
901}
902
904{
905 return m_array.length();
906}
907
909{
910 if (pos >= size())
911 return false;
912 return QIODevice::seek(pos);
913}
914
916{
917 uint64_t begin = QIODevice::pos();
918 uint64_t end = std::min<uint64_t>(begin + maxSize, size());
919 uint64_t size = end - begin;
920 if (size > 0)
921 m_array.subarray(begin, end).copyTo(data);
922 return size;
923}
924
926{
927 uint64_t begin = QIODevice::pos();
928 uint64_t end = std::min<uint64_t>(begin + maxSize, size());
929 uint64_t size = end - begin;
930 if (size > 0)
931 m_array.subarray(begin, end).set(Uint8Array(data, size));
932 return size;
933}
934
935} // namespace qstdweb
936
\inmodule QtGui
\inmodule QtCore
Definition qbytearray.h:57
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
\inmodule QtCore
Definition qeventloop.h:16
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
Definition qstring.h:129
static QString fromStdString(const std::string &s)
Definition qstring.h:1447
std::string toStdString() const
Returns a std::string object with the data contained in this QString.
Definition qstring.h:1444
ArrayBuffer slice(uint32_t begin, uint32_t end) const
Definition qstdweb.cpp:397
emscripten::val val() const
Definition qstdweb.cpp:402
uint32_t byteLength() const
Definition qstdweb.cpp:389
ArrayBuffer(uint32_t size)
Definition qstdweb.cpp:378
bool seek(qint64 pos) override
For random-access devices, this function sets the current position to pos, returning true on success,...
Definition qstdweb.cpp:863
bool isSequential() const override
Returns true if this device is sequential; otherwise returns false.
Definition qstdweb.cpp:853
qint64 writeData(const char *, qint64) override
Writes up to maxSize bytes from data to the device.
Definition qstdweb.cpp:882
BlobIODevice(Blob blob)
Definition qstdweb.cpp:840
qint64 size() const override
For open random-access devices, this function returns the size of the device.
Definition qstdweb.cpp:858
bool open(QIODeviceBase::OpenMode mode) override
Opens the device and sets its OpenMode to mode.
Definition qstdweb.cpp:846
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...
Definition qstdweb.cpp:870
Blob slice(uint32_t begin, uint32_t end) const
Definition qstdweb.cpp:442
ArrayBuffer arrayBuffer_sync() const
Definition qstdweb.cpp:447
uint32_t size() const
Definition qstdweb.cpp:420
std::string type() const
Definition qstdweb.cpp:498
Blob(const emscripten::val &blob)
Definition qstdweb.cpp:407
static Blob copyFrom(const char *buffer, uint32_t size, std::string mimeType)
Definition qstdweb.cpp:425
emscripten::val val() const
Definition qstdweb.cpp:461
static Blob fromArrayBuffer(const ArrayBuffer &arrayBuffer)
Definition qstdweb.cpp:413
void handleEvent(emscripten::val event)
Definition qstdweb.cpp:728
EventListener(uintptr_t handler)
Definition qstdweb.cpp:720
FileList()=default
File item(int index) const
Definition qstdweb.cpp:555
int length() const
Definition qstdweb.cpp:550
emscripten::val val() const
Definition qstdweb.cpp:565
File operator[](int index) const
Definition qstdweb.cpp:560
void onAbort(const std::function< void(emscripten::val)> &onAbort)
Definition qstdweb.cpp:592
ArrayBuffer result() const
Definition qstdweb.cpp:570
void onLoad(const std::function< void(emscripten::val)> &onLoad)
Definition qstdweb.cpp:580
void readAsArrayBuffer(const Blob &blob) const
Definition qstdweb.cpp:575
void onError(const std::function< void(emscripten::val)> &onError)
Definition qstdweb.cpp:586
emscripten::val val() const
Definition qstdweb.cpp:598
FileUrlRegistration & operator=(const FileUrlRegistration &other)=delete
uint64_t size() const
Definition qstdweb.cpp:493
qint64 size() const override
For open random-access devices, this function returns the size of the device.
Definition qstdweb.cpp:903
bool seek(qint64 pos) override
For random-access devices, this function sets the current position to pos, returning true on success,...
Definition qstdweb.cpp:908
Uint8ArrayIODevice(Uint8Array array)
Definition qstdweb.cpp:887
bool isSequential() const override
Returns true if this device is sequential; otherwise returns false.
Definition qstdweb.cpp:898
qint64 writeData(const char *data, qint64 size) override
Writes up to maxSize bytes from data to the device.
Definition qstdweb.cpp:925
bool open(QIODevice::OpenMode mode) override
Definition qstdweb.cpp:893
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...
Definition qstdweb.cpp:915
emscripten::val val() const
Definition qstdweb.cpp:703
void copyTo(char *destination) const
Definition qstdweb.cpp:666
static Uint8Array heap()
Definition qstdweb.cpp:603
Uint8Array subarray(uint32_t begin, uint32_t end)
Definition qstdweb.cpp:658
void set(const Uint8Array &source)
Definition qstdweb.cpp:653
ArrayBuffer buffer() const
Definition qstdweb.cpp:643
QByteArray copyToQByteArray() const
Definition qstdweb.cpp:672
Uint8Array(const emscripten::val &uint8Array)
Definition qstdweb.cpp:609
static Uint8Array copyFrom(const char *buffer, uint32_t size)
Definition qstdweb.cpp:690
uint32_t length() const
Definition qstdweb.cpp:648
static void copy(char *destination, const Uint8Array &source)
Definition qstdweb.cpp:684
else opt state
[0]
Combined button and popup list for selecting options.
void make(emscripten::val target, QString methodName, PromiseCallbacks callbacks, Args... args)
Definition qstdweb_p.h:221
void adoptPromise(emscripten::val promiseObject, PromiseCallbacks callbacks)
Definition qstdweb.cpp:760
void all(std::vector< emscripten::val > promises, PromiseCallbacks callbacks)
Definition qstdweb.cpp:767
bool canBlockCallingThread()
Definition qstdweb.cpp:835
double uint53_t
Definition qstdweb.cpp:41
bool haveJspi()
Definition qstdweb.cpp:823
bool haveAsyncify()
Definition qstdweb.cpp:829
static void usePotentialyUnusedSymbols()
Definition qstdweb.cpp:26
EMSCRIPTEN_BINDINGS(qtStdwebCalback)
Definition qstdweb.cpp:753
static void * context
#define Q_LIKELY(x)
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)()
EGLStreamKHR stream
const char * mimeType
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
GLenum mode
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum GLuint id
[7]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint buffer
GLenum type
GLenum target
GLenum GLuint GLintptr offset
GLuint name
GLsizei GLsizei GLchar * source
struct _cl_event * event
GLuint GLfloat * val
GLenum array
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
std::unique_ptr< ThunkPool::ThunkAllocation > allocation
Definition qstdweb.cpp:276
PromiseCallbacks callbacks
Definition qstdweb.cpp:275
#define THUNK(i)
Definition qstdweb.cpp:188
static constexpr size_t poolSize
Definition qstdweb.cpp:112
#define CALLBACK_BINDING(i)
Definition qstdweb.cpp:240
#define QStringLiteral(str)
decltype(openFileForWriting({})) File
Definition main.cpp:76
long long qint64
Definition qtypes.h:60
ReturnedValue read(const char *data)
QFile file
[0]
QSharedPointer< T > other(t)
[5]
QGraphicsItem * item
std::function< void(emscripten::val)> thenFunc
Definition qstdweb_p.h:212
std::function< void()> finallyFunc
Definition qstdweb_p.h:214
std::function< void(emscripten::val)> catchFunc
Definition qstdweb_p.h:213