@@ -151,8 +151,17 @@ void HTMLImageElement::form_associated_element_attribute_changed(FlyString const
151151 }
152152
153153 if (name == HTML::AttributeNames::decoding) {
154- if (value.has_value () && (value->equals_ignoring_ascii_case (" sync" sv) || value->equals_ignoring_ascii_case (" async" sv)))
155- dbgln (" FIXME: HTMLImageElement.decoding = '{}' is not implemented yet" , value->to_ascii_lowercase ());
154+ if (value.has_value ()) {
155+ auto decoding_value = value -> to_ascii_lowercase ();
156+ if (decoding_value == " sync" sv)
157+ m_decoding_mode = DecodingMode::Sync;
158+ else if (decoding_value == " async" sv)
159+ m_decoding_mode = DecodingMode::Async;
160+ else
161+ m_decoding_mode = DecodingMode::Auto;
162+ } else {
163+ m_decoding_mode = DecodingMode::Auto;
164+ }
156165 }
157166}
158167
@@ -343,93 +352,134 @@ WebIDL::ExceptionOr<GC::Ref<WebIDL::Promise>> HTMLImageElement::decode() const
343352 // 1. Let promise be a new promise.
344353 auto promise = WebIDL::create_promise (realm);
345354
346- // 2. Queue a microtask to perform the following steps:
347- queue_a_microtask (&document (), GC::create_function (realm.heap (), [this , promise, &realm]() mutable {
348- // 1. Let global be this's relevant global object.
349- auto & global = relevant_global_object (*this );
350-
351- auto reject_if_document_not_fully_active = [this , promise, &realm]() -> bool {
352- if (this ->document ().is_fully_active ())
353- return false ;
354-
355- auto exception = WebIDL::EncodingError::create (realm, " Node document not fully active" _utf16);
356- HTML::TemporaryExecutionContext context (realm);
357- WebIDL::reject_promise (realm, promise, exception);
358- return true ;
359- };
360-
361- auto reject_if_current_request_state_broken = [this , promise, &realm]() {
362- if (this ->current_request ().state () != ImageRequest::State::Broken)
363- return false ;
364-
365- auto exception = WebIDL::EncodingError::create (realm, " Current request state is broken" _utf16);
366- HTML::TemporaryExecutionContext context (realm);
367- WebIDL::reject_promise (realm, promise, exception);
368- return true ;
369- };
370-
371- // 2. If any of the following are true:
372- // - this's node document is not fully active;
373- // - or this's current request's state is broken,
374- // then reject promise with an "EncodingError" DOMException.
375- if (reject_if_document_not_fully_active () || reject_if_current_request_state_broken ()) {
376- return ;
355+ if (m_decoding_mode == DecodingMode::Sync) {
356+ // SYNC DECODING
357+ // Warning: This will block the main thread until the image is decoded.
358+ if (!document ().is_fully_active ()) {
359+ WebIDL::reject_promise (realm, promise, WebIDL::EncodingError::create (realm, " Node document not fully active" _utf16));
360+ return promise;
361+ }
362+ if (current_request ().state () == ImageRequest::State::Broken) {
363+ WebIDL::reject_promise (realm, promise, WebIDL::EncodingError::create (realm, " Current request state is broken" _utf16));
364+ return promise;
365+ }
366+ if (current_request ().state () != ImageRequest::State::CompletelyAvailable) {
367+ WebIDL::reject_promise (realm, promise, WebIDL::EncodingError::create (realm, " Image data not available" _utf16));
368+ return promise;
377369 }
378370
379- // 3. Otherwise, in parallel wait for one of the following cases to occur, and perform the corresponding actions:
380- Platform::EventLoopPlugin::the ().deferred_invoke (GC::create_function (heap (), [this , promise, &realm, &global] {
381- Platform::EventLoopPlugin::the ().spin_until (GC::create_function (heap (), [this , promise, &realm, &global] {
382- auto queue_reject_task = [promise, &realm, &global](Utf16String message) {
383- queue_global_task (Task::Source::DOMManipulation, global, GC::create_function (realm.heap (), [&realm, promise, message = move (message)] {
384- auto exception = WebIDL::EncodingError::create (realm, message);
385- HTML::TemporaryExecutionContext context (realm);
386- WebIDL::reject_promise (realm, promise, exception);
387- }));
388- };
389-
390- // -> This img element's node document stops being fully active
391- if (!document ().is_fully_active ()) {
392- // Queue a global task on the DOM manipulation task source with global to reject promise with an "EncodingError" DOMException.
393- queue_reject_task (" Node document not fully active" _utf16);
394- return true ;
395- }
371+ if (!current_request ().shared_resource_request () || current_request ().shared_resource_request ()->encoded_data ().is_empty ()) {
372+ WebIDL::reject_promise (realm, promise, WebIDL::EncodingError::create (realm, " Image data not available" _utf16));
373+ return promise;
374+ }
396375
397- auto state = this ->current_request ().state ();
376+ bool success = false ;
377+ bool failed = false ;
398378
399- // -> FIXME: This img element's current request changes or is mutated
400- if (false ) {
401- // Queue a global task on the DOM manipulation task source with global to reject promise with an "EncodingError" DOMException.
402- queue_reject_task (" Current request changed or was mutated" _utf16);
403- return true ;
404- }
379+ (void )Web::Platform::ImageCodecPlugin::the ().decode_image (
380+ current_request ().shared_resource_request ()->encoded_data (),
381+ [&](Web::Platform::DecodedImage&) -> ErrorOr<void > {
382+ success = true ;
383+ return {};
384+ },
385+ [&](auto &) {
386+ failed = true ;
387+ });
405388
406- // -> This img element's current request's state becomes broken
407- if (state == ImageRequest::State::Broken) {
408- // Queue a global task on the DOM manipulation task source with global to reject promise with an "EncodingError" DOMException.
409- queue_reject_task (" Current request state is broken" _utf16);
410- return true ;
411- }
389+ Core::EventLoop::current ().spin_until ([&] {
390+ return success || failed;
391+ });
412392
413- // -> This img element's current request's state becomes completely available
414- if (state == ImageRequest::State::CompletelyAvailable) {
415- // FIXME: Decode the image.
416- // 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.
417- // 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.
418-
419- // NOTE: For now we just resolve it.
420- queue_global_task (Task::Source::DOMManipulation, global, GC::create_function (realm.heap (), [&realm, promise] {
421- HTML::TemporaryExecutionContext context (realm);
422- WebIDL::resolve_promise (realm, promise, JS::js_undefined ());
423- }));
424- return true ;
425- }
393+ if (success) {
394+ WebIDL::resolve_promise (realm, promise, JS::js_undefined ());
395+ } else {
396+ WebIDL::reject_promise (realm, promise, WebIDL::EncodingError::create (realm, " Decoding failed" _utf16));
397+ }
398+
399+ } else { // ASYNC / AUTO DECODING
400+ queue_a_microtask (&document (), GC::create_function (realm.heap (), [this , promise, &realm]() mutable {
401+ auto & global = relevant_global_object (*this );
402+
403+ auto reject_if_document_not_fully_active = [this , promise, &realm]() -> bool {
404+ if (this ->document ().is_fully_active ())
405+ return false ;
406+
407+ auto exception = WebIDL::EncodingError::create (realm, " Node document not fully active" _utf16);
408+ HTML::TemporaryExecutionContext context (realm);
409+ WebIDL::reject_promise (realm, promise, exception);
410+ return true ;
411+ };
412+
413+ auto reject_if_current_request_state_broken = [this , promise, &realm]() {
414+ if (this ->current_request ().state () != ImageRequest::State::Broken)
415+ return false ;
416+
417+ auto exception = WebIDL::EncodingError::create (realm, " Current request state is broken" _utf16);
418+ HTML::TemporaryExecutionContext context (realm);
419+ WebIDL::reject_promise (realm, promise, exception);
420+ return true ;
421+ };
426422
427- return false ;
423+ if (reject_if_document_not_fully_active () || reject_if_current_request_state_broken ()) {
424+ return ;
425+ }
426+
427+ Platform::EventLoopPlugin::the ().deferred_invoke (GC::create_function (heap (), [this , promise, &realm, &global] {
428+ Platform::EventLoopPlugin::the ().spin_until (GC::create_function (heap (), [this , promise, &realm, &global] {
429+ auto queue_reject_task = [promise, &realm, &global](Utf16String message) {
430+ queue_global_task (Task::Source::DOMManipulation, global, GC::create_function (realm.heap (), [&realm, promise, message = move (message)] {
431+ auto exception = WebIDL::EncodingError::create (realm, message);
432+ HTML::TemporaryExecutionContext context (realm);
433+ WebIDL::reject_promise (realm, promise, exception);
434+ }));
435+ };
436+
437+ if (!document ().is_fully_active ()) {
438+ queue_reject_task (" Node document not fully active" _utf16);
439+ return true ;
440+ }
441+
442+ auto state = this ->current_request ().state ();
443+
444+ if (false ) { // FIXME: This img element's current request changes or is mutated
445+ queue_reject_task (" Current request changed or was mutated" _utf16);
446+ return true ;
447+ }
448+
449+ if (state == ImageRequest::State::Broken) {
450+ queue_reject_task (" Current request state is broken" _utf16);
451+ return true ;
452+ }
453+
454+ if (state == ImageRequest::State::CompletelyAvailable) {
455+ auto & image_request = this ->current_request ();
456+ if (!image_request.shared_resource_request () || image_request.shared_resource_request ()->encoded_data ().is_empty ()) {
457+ queue_reject_task (" Image data not available" _utf16);
458+ return true ;
459+ }
460+
461+ (void )Web::Platform::ImageCodecPlugin::the ().decode_image (
462+ image_request.shared_resource_request ()->encoded_data (),
463+ [promise, &realm, &global](Web::Platform::DecodedImage&) -> ErrorOr<void > {
464+ queue_global_task (Task::Source::DOMManipulation, global, GC::create_function (realm.heap (), [&realm, promise] {
465+ HTML::TemporaryExecutionContext context (realm);
466+ WebIDL::resolve_promise (realm, promise, JS::js_undefined ());
467+ }));
468+ return {};
469+ },
470+ [promise, &realm, &global, &queue_reject_task](auto &) {
471+ queue_reject_task (" Decoding failed" _utf16);
472+ });
473+
474+ return true ;
475+ }
476+
477+ return false ;
478+ }));
428479 }));
429480 }));
430- }));
481+ }
431482
432- // 3. Return promise.
433483 return promise;
434484}
435485
0 commit comments