diff --git a/src/corelib/platform/wasm/qstdweb.cpp b/src/corelib/platform/wasm/qstdweb.cpp index 789ceda6ab..fc2bf9cf96 100644 --- a/src/corelib/platform/wasm/qstdweb.cpp +++ b/src/corelib/platform/wasm/qstdweb.cpp @@ -49,6 +49,11 @@ namespace qstdweb { typedef double uint53_t; // see Number.MAX_SAFE_INTEGER +ArrayBuffer::ArrayBuffer(uint32_t size) +{ + m_arrayBuffer = emscripten::val::global("ArrayBuffer").new_(size); +} + ArrayBuffer::ArrayBuffer(const emscripten::val &arrayBuffer) :m_arrayBuffer(arrayBuffer) { @@ -74,6 +79,23 @@ uint32_t Blob::size() const return m_blob["size"].as(); } +// Copies content from the given buffer into a Blob object +Blob Blob::copyFrom(const char *buffer, uint32_t size) +{ + Uint8Array contentCopy = Uint8Array::copyFrom(buffer, size); + + emscripten::val contentArray = emscripten::val::array(); + contentArray.call("push", contentCopy.m_uint8Array); + emscripten::val type = emscripten::val::object(); + type.set("type","application/octet-stream"); + return Blob(emscripten::val::global("Blob").new_(contentArray, type)); +} + +emscripten::val Blob::val() +{ + return m_blob; +} + File::File(const emscripten::val &file) :m_file(file) { @@ -191,30 +213,41 @@ Uint8Array Uint8Array::heap() return Uint8Array(heap_()); } +// Constructs a Uint8Array which references the given emscripten::val, which must contain a JS Unit8Array Uint8Array::Uint8Array(const emscripten::val &uint8Array) : m_uint8Array(uint8Array) { } +// Constructs a Uint8Array which references an ArrayBuffer Uint8Array::Uint8Array(const ArrayBuffer &buffer) : m_uint8Array(Uint8Array::constructor_().new_(buffer.m_arrayBuffer)) { } +// Constructs a Uint8Array which references a view into an ArrayBuffer Uint8Array::Uint8Array(const ArrayBuffer &buffer, uint32_t offset, uint32_t length) : m_uint8Array(Uint8Array::constructor_().new_(buffer.m_arrayBuffer, offset, length)) { } -Uint8Array::Uint8Array(char *buffer, uint32_t size) +// Constructs a Uint8Array which references an area on the heap. +Uint8Array::Uint8Array(const char *buffer, uint32_t size) :m_uint8Array(Uint8Array::constructor_().new_(Uint8Array::heap().buffer().m_arrayBuffer, uint32_t(buffer), size)) { } +// Constructs a Uint8Array which allocates and references a new ArrayBuffer with the given size. +Uint8Array::Uint8Array(uint32_t size) +: m_uint8Array(Uint8Array::constructor_().new_(size)) +{ + +} + ArrayBuffer Uint8Array::buffer() const { return ArrayBuffer(m_uint8Array["buffer"]); @@ -230,16 +263,26 @@ void Uint8Array::set(const Uint8Array &source) m_uint8Array.call("set", source.m_uint8Array); // copies source content } +// Copies the Uint8Array conent to a destination on the heap void Uint8Array::copyTo(char *destination) const { Uint8Array(destination, length()).set(*this); } +// Copies the Uint8Array conent to a destination on the heap void Uint8Array::copy(char *destination, const Uint8Array &source) { Uint8Array(destination, source.length()).set(source); } +// Copies content from a source on the heap to a new Uint8Array object +Uint8Array Uint8Array::copyFrom(const char *buffer, uint32_t size) +{ + Uint8Array contentCopy(size); + contentCopy.set(Uint8Array(buffer, size)); + return contentCopy; +} + emscripten::val Uint8Array::heap_() { return emscripten::val::module_property("HEAPU8"); diff --git a/src/corelib/platform/wasm/qstdweb_p.h b/src/corelib/platform/wasm/qstdweb_p.h index ff83c73dd5..fc52dc1a71 100644 --- a/src/corelib/platform/wasm/qstdweb_p.h +++ b/src/corelib/platform/wasm/qstdweb_p.h @@ -73,6 +73,7 @@ namespace qstdweb { class ArrayBuffer { public: + explicit ArrayBuffer(uint32_t size); explicit ArrayBuffer(const emscripten::val &arrayBuffer); uint32_t byteLength() const; @@ -85,6 +86,8 @@ namespace qstdweb { public: explicit Blob(const emscripten::val &blob); uint32_t size() const; + static Blob copyFrom(const char *buffer, uint32_t size); + emscripten::val val(); private: friend class FileReader; @@ -140,8 +143,9 @@ namespace qstdweb { static Uint8Array heap(); explicit Uint8Array(const emscripten::val &uint8Array); explicit Uint8Array(const ArrayBuffer &buffer); + explicit Uint8Array(uint32_t size); Uint8Array(const ArrayBuffer &buffer, uint32_t offset, uint32_t length); - Uint8Array(char *buffer, uint32_t size); + Uint8Array(const char *buffer, uint32_t size); ArrayBuffer buffer() const; uint32_t length() const; @@ -149,7 +153,9 @@ namespace qstdweb { void copyTo(char *destination) const; static void copy(char *destination, const Uint8Array &source); + static Uint8Array copyFrom(const char *buffer, uint32_t size); private: + friend class Blob; static emscripten::val heap_(); static emscripten::val constructor_(); emscripten::val m_uint8Array = emscripten::val::undefined(); diff --git a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp index e810a1ad8e..76e9c6c519 100644 --- a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp +++ b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp @@ -129,27 +129,13 @@ void openFile(const std::string &accept, void saveFile(const char *content, size_t size, const std::string &fileNameHint) { // Save a file by creating programmatically clicking a download - // link to an object url to a Blob containing the file content. - // File content is copied once, so that the passed in content - // buffer can be released as soon as this function returns - we - // don't know for how long the browser will retain the TypedArray - // view used to create the Blob. - + // link to an object url to a Blob containing a copy of the file + // content. The copy is made so that the passed in content buffer + // can be released as soon as this function returns. + qstdweb::Blob contentBlob = qstdweb::Blob::copyFrom(content, size); emscripten::val document = emscripten::val::global("document"); emscripten::val window = emscripten::val::global("window"); - - emscripten::val fileContentView = emscripten::val(emscripten::typed_memory_view(size, content)); - emscripten::val fileContentCopy = emscripten::val::global("ArrayBuffer").new_(size); - emscripten::val fileContentCopyView = emscripten::val::global("Uint8Array").new_(fileContentCopy); - fileContentCopyView.call("set", fileContentView); - - emscripten::val contentArray = emscripten::val::array(); - contentArray.call("push", fileContentCopyView); - emscripten::val type = emscripten::val::object(); - type.set("type","application/octet-stream"); - emscripten::val contentBlob = emscripten::val::global("Blob").new_(contentArray, type); - - emscripten::val contentUrl = window["URL"].call("createObjectURL", contentBlob); + emscripten::val contentUrl = window["URL"].call("createObjectURL", contentBlob.val()); emscripten::val contentLink = document.call("createElement", std::string("a")); contentLink.set("href", contentUrl); contentLink.set("download", fileNameHint);