diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/Task.h b/Userland/Libraries/LibWeb/HTML/EventLoop/Task.h
index ba3e0f13f2..3ac67b256c 100644
--- a/Userland/Libraries/LibWeb/HTML/EventLoop/Task.h
+++ b/Userland/Libraries/LibWeb/HTML/EventLoop/Task.h
@@ -44,6 +44,9 @@ public:
// Some elements, such as the HTMLMediaElement, must have a unique task source per instance.
// Keep this field last, to serve as the base value of all unique task sources.
UniqueTaskSourceStart,
+
+ // https://html.spec.whatwg.org/multipage/canvas.html#canvas-blob-serialisation-task-source
+ CanvasBlobSerializationTask,
};
static NonnullOwnPtr create(Source source, DOM::Document const* document, JS::SafeFunction steps)
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp
index dab91433f2..d5277ccff8 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp
@@ -8,11 +8,15 @@
#include
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
+#include
+#include
namespace Web::HTML {
@@ -219,6 +223,47 @@ DeprecatedString HTMLCanvasElement::to_data_url(DeprecatedString const& type, Op
return AK::URL::create_with_data(file.value().mime_type, base64_encoded_or_error.release_value(), true).to_deprecated_string();
}
+// https://html.spec.whatwg.org/multipage/canvas.html#dom-canvas-toblob
+WebIDL::ExceptionOr HTMLCanvasElement::to_blob(JS::NonnullGCPtr callback, DeprecatedString const& type, Optional quality)
+{
+ // FIXME: 1. If this canvas element's bitmap's origin-clean flag is set to false, then throw a "SecurityError" DOMException.
+
+ // 2. Let result be null.
+ RefPtr bitmap_result;
+
+ // 3. If this canvas element's bitmap has pixels (i.e., neither its horizontal dimension nor its vertical dimension is zero),
+ // then set result to a copy of this canvas element's bitmap.
+ if (m_bitmap)
+ bitmap_result = TRY_OR_THROW_OOM(vm(), m_bitmap->clone());
+
+ // 4. Run these steps in parallel:
+ Platform::EventLoopPlugin::the().deferred_invoke([this, callback, bitmap_result, type, quality] {
+ // 1. If result is non-null, then set result to a serialization of result as a file with type and quality if given.
+ Optional file_result;
+ if (bitmap_result) {
+ if (auto result = serialize_bitmap(*bitmap_result, type, move(quality)); !result.is_error())
+ file_result = result.release_value();
+ }
+
+ // 2. Queue an element task on the canvas blob serialization task source given the canvas element to run these steps:
+ queue_an_element_task(Task::Source::CanvasBlobSerializationTask, [this, callback, file_result = move(file_result)] {
+ auto maybe_error = Bindings::throw_dom_exception_if_needed(vm(), [&]() -> WebIDL::ExceptionOr {
+ // 1. If result is non-null, then set result to a new Blob object, created in the relevant realm of this canvas element, representing result. [FILEAPI]
+ JS::GCPtr blob_result;
+ if (file_result.has_value())
+ blob_result = TRY(FileAPI::Blob::create(realm(), file_result->buffer, TRY_OR_THROW_OOM(vm(), String::from_utf8(file_result->mime_type))));
+
+ // 2. Invoke callback with « result ».
+ TRY(WebIDL::invoke_callback(*callback, {}, move(blob_result)));
+ return {};
+ });
+ if (maybe_error.is_throw_completion())
+ report_exception(maybe_error.throw_completion(), realm());
+ });
+ });
+ return {};
+}
+
void HTMLCanvasElement::present()
{
m_context.visit(
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.h b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.h
index 881ddd777d..63906ebc89 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.h
+++ b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.h
@@ -34,6 +34,7 @@ public:
WebIDL::ExceptionOr set_height(unsigned);
DeprecatedString to_data_url(DeprecatedString const& type, Optional quality) const;
+ WebIDL::ExceptionOr to_blob(JS::NonnullGCPtr callback, DeprecatedString const& type, Optional quality);
void present();
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.idl b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.idl
index 90df720626..6ea01e08fd 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.idl
+++ b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.idl
@@ -15,5 +15,7 @@ interface HTMLCanvasElement : HTMLElement {
[CEReactions] attribute unsigned long height;
USVString toDataURL(optional DOMString type = "image/png", optional double quality);
-
+ undefined toBlob(BlobCallback _callback, optional DOMString type = "image/png", optional double quality);
};
+
+callback BlobCallback = undefined (Blob? blob);