From e382fb4dab30770d88c217cc669c9da36b80dbab Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 14 Nov 2024 10:41:08 +0000 Subject: [PATCH] LibWeb/HTML: Resolve image decoding promises inside tasks This corresponds to https://github.com/whatwg/html/pull/10753 WHile I was at it, I've also moved the checks inside the spin callback, and reformatted the spec comments to match our style. --- Libraries/LibWeb/HTML/HTMLImageElement.cpp | 92 +++++++++++++--------- 1 file changed, 54 insertions(+), 38 deletions(-) diff --git a/Libraries/LibWeb/HTML/HTMLImageElement.cpp b/Libraries/LibWeb/HTML/HTMLImageElement.cpp index cb5e9fbd83d4..e8621d1ae9b1 100644 --- a/Libraries/LibWeb/HTML/HTMLImageElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLImageElement.cpp @@ -293,6 +293,9 @@ WebIDL::ExceptionOr> HTMLImageElement::decode( // 2. Queue a microtask to perform the following steps: queue_a_microtask(&document(), JS::create_heap_function(realm.heap(), [this, promise, &realm]() mutable { + // 1. Let global be this's relevant global object. + auto& global = relevant_global_object(*this); + auto reject_if_document_not_fully_active = [this, promise, &realm]() -> bool { if (this->document().is_fully_active()) return false; @@ -313,55 +316,68 @@ WebIDL::ExceptionOr> HTMLImageElement::decode( return true; }; - // 2.1 If any of the following are true: - // 2.1.1 this's node document is not fully active; - // 2.1.1 then reject promise with an "EncodingError" DOMException. - if (reject_if_document_not_fully_active()) - return; - - // 2.1.2 or this's current request's state is broken, - // 2.1.2 then reject promise with an "EncodingError" DOMException. - if (reject_if_current_request_state_broken()) + // 2. If any of the following are true: + // - this's node document is not fully active; + // - or this's current request's state is broken, + // then reject promise with an "EncodingError" DOMException. + if (reject_if_document_not_fully_active() || reject_if_current_request_state_broken()) { return; + } - // 2.2 Otherwise, in parallel wait for one of the following cases to occur, and perform the corresponding actions: - Platform::EventLoopPlugin::the().deferred_invoke(JS::create_heap_function(heap(), [this, promise, &realm, reject_if_document_not_fully_active, reject_if_current_request_state_broken] { + // 3. Otherwise, in parallel wait for one of the following cases to occur, and perform the corresponding actions: + Platform::EventLoopPlugin::the().deferred_invoke(JS::create_heap_function(heap(), [this, promise, &realm, &global] { Platform::EventLoopPlugin::the().spin_until(JS::create_heap_function(heap(), [&] { - auto state = this->current_request().state(); + auto queue_reject_task = [&](String const& message) { + queue_global_task(Task::Source::DOMManipulation, global, JS::create_heap_function(realm.heap(), [&realm, &promise, &message] { + auto exception = WebIDL::EncodingError::create(realm, message); + HTML::TemporaryExecutionContext context(realm); + WebIDL::reject_promise(realm, promise, exception); + })); + }; + + // -> This img element's node document stops being fully active + if (!document().is_fully_active()) { + // Queue a global task on the DOM manipulation task source with global to reject promise with an "EncodingError" DOMException. + queue_reject_task("Node document not fully active"_string); + return true; + } - return !this->document().is_fully_active() || state == ImageRequest::State::Broken || state == ImageRequest::State::CompletelyAvailable; - })); + auto state = this->current_request().state(); - // 2.2.1 This img element's node document stops being fully active - // 2.2.1 Reject promise with an "EncodingError" DOMException. - if (reject_if_document_not_fully_active()) - return; + // -> FIXME: This img element's current request changes or is mutated + if (false) { + // Queue a global task on the DOM manipulation task source with global to reject promise with an "EncodingError" DOMException. + queue_reject_task("Current request changed or was mutated"_string); + return true; + } - // FIXME: 2.2.2 This img element's current request changes or is mutated - // FIXME: 2.2.2 Reject promise with an "EncodingError" DOMException. + // -> This img element's current request's state becomes broken + if (state == ImageRequest::State::Broken) { + // Queue a global task on the DOM manipulation task source with global to reject promise with an "EncodingError" DOMException. + queue_reject_task("Current request state is broken"_string); + return true; + } - // 2.2.3 This img element's current request's state becomes broken - // 2.2.3 Reject promise with an "EncodingError" DOMException. - if (reject_if_current_request_state_broken()) - return; + // -> This img element's current request's state becomes completely available + if (state == ImageRequest::State::CompletelyAvailable) { + // FIXME: Decode the image. + // FIXME: If decoding does not need to be performed for this image (for example because it is a vector graphic) or the decoding process completes successfully, then queue a global task on the DOM manipulation task source with global to resolve promise with undefined. + // FIXME: If decoding fails (for example due to invalid image data), then queue a global task on the DOM manipulation task source with global to reject promise with an "EncodingError" DOMException. + + // NOTE: For now we just resolve it. + queue_global_task(Task::Source::DOMManipulation, global, JS::create_heap_function(realm.heap(), [&realm, &promise] { + HTML::TemporaryExecutionContext context(realm); + WebIDL::resolve_promise(realm, promise, JS::js_undefined()); + })); + return true; + } - // 2.2.4 This img element's current request's state becomes completely available - if (this->current_request().state() == ImageRequest::State::CompletelyAvailable) { - // 2.2.4.1 FIXME: Decode the image. - // 2.2.4.2 FIXME: If decoding does not need to be performed for this image (for example because it is a vector graphic), resolve promise with undefined. - // 2.2.4.3 FIXME: If decoding fails (for example due to invalid image data), reject promise with an "EncodingError" DOMException. - // 2.2.4.4 FIXME: If the decoding process completes successfully, resolve promise with undefined. - // 2.2.4.5 FIXME: User agents should ensure that the decoded media data stays readily available until at least the end of the next successful update - // the rendering step in the event loop. This is an important part of the API contract, and should not be broken if at all possible. - // (Typically, this would only be violated in low-memory situations that require evicting decoded image data, or when the image is too large - // to keep in decoded form for this period of time.) - - HTML::TemporaryExecutionContext context(realm); - WebIDL::resolve_promise(realm, promise, JS::js_undefined()); - } + return false; + })); })); })); + // 3. Return promise. return promise; }