20
20
#include < LibWeb/HTML/HTMLAudioElement.h>
21
21
#include < LibWeb/HTML/HTMLMediaElement.h>
22
22
#include < LibWeb/HTML/HTMLVideoElement.h>
23
+ #include < LibWeb/HTML/MediaError.h>
23
24
#include < LibWeb/HTML/PotentialCORSRequest.h>
24
25
#include < LibWeb/HTML/Scripting/Environments.h>
25
26
#include < LibWeb/HTML/TimeRanges.h>
@@ -81,6 +82,7 @@ void HTMLMediaElement::queue_a_media_element_task(JS::SafeFunction<void()> steps
81
82
void HTMLMediaElement::visit_edges (Cell::Visitor& visitor)
82
83
{
83
84
Base::visit_edges (visitor);
85
+ visitor.visit (m_error);
84
86
visitor.visit (m_fetch_controller);
85
87
visitor.visit (m_video_tracks);
86
88
}
@@ -251,8 +253,14 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> HTMLMediaElement::play()
251
253
252
254
// FIXME: 1. If the media element is not allowed to play, then return a promise rejected with a "NotAllowedError" DOMException.
253
255
254
- // FIXME: 2. If the media element's error attribute is not null and its code is MEDIA_ERR_SRC_NOT_SUPPORTED, then return a promise
255
- // rejected with a "NotSupportedError" DOMException.
256
+ // 2. If the media element's error attribute is not null and its code is MEDIA_ERR_SRC_NOT_SUPPORTED, then return a promise
257
+ // rejected with a "NotSupportedError" DOMException.
258
+ if (m_error && m_error->code () == MediaError::Code::SrcNotSupported) {
259
+ auto error = WebIDL::NotSupportedError::create (realm, m_error->message ().to_deprecated_string ());
260
+ auto promise = WebIDL::create_rejected_promise (realm, error);
261
+
262
+ return JS::NonnullGCPtr { verify_cast<JS::Promise>(*promise->promise ()) };
263
+ }
256
264
257
265
// 3. Let promise be a new promise and append promise to the list of pending play promises.
258
266
auto promise = WebIDL::create_promise (realm);
@@ -361,7 +369,7 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::load_element()
361
369
// FIXME: 7. Set the playbackRate attribute to the value of the defaultPlaybackRate attribute.
362
370
363
371
// 8. Set the error attribute to null and the can autoplay flag to true.
364
- // FIXME: Handle the error attribute.
372
+ m_error = nullptr ;
365
373
m_can_autoplay = true ;
366
374
367
375
// 9. Invoke the media element's resource selection algorithm.
@@ -444,14 +452,14 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::select_resource()
444
452
445
453
// -> If mode is attribute
446
454
case SelectMode::Attribute: {
447
- auto failed_with_attribute = [this ]() {
455
+ auto failed_with_attribute = [this ](auto error_message ) {
448
456
bool ran_media_element_task = false ;
449
457
450
458
// 6. Failed with attribute: Reaching this step indicates that the media resource failed to load or that the given URL could not be parsed. Take
451
459
// pending play promises and queue a media element task given the media element to run the dedicated media source failure steps with the result.
452
- queue_a_media_element_task ([this , &ran_media_element_task]() {
460
+ queue_a_media_element_task ([this , &ran_media_element_task, error_message = move (error_message) ]() mutable {
453
461
auto promises = take_pending_play_promises ();
454
- handle_media_source_failure (promises).release_value_but_fixme_should_propagate_errors ();
462
+ handle_media_source_failure (promises, move (error_message) ).release_value_but_fixme_should_propagate_errors ();
455
463
456
464
ran_media_element_task = true ;
457
465
});
@@ -463,7 +471,7 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::select_resource()
463
471
// 1. ⌛ If the src attribute's value is the empty string, then end the synchronous section, and jump down to the failed with attribute step below.
464
472
auto source = attribute (HTML::AttributeNames::src);
465
473
if (source.is_empty ()) {
466
- failed_with_attribute ();
474
+ failed_with_attribute (TRY_OR_THROW_OOM (vm, " The 'src' attribute is empty " _string) );
467
475
return {};
468
476
}
469
477
@@ -484,7 +492,7 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::select_resource()
484
492
return {};
485
493
}
486
494
487
- failed_with_attribute ();
495
+ failed_with_attribute (TRY_OR_THROW_OOM (vm, " Failed to parse 'src' attribute as a URL " _string) );
488
496
489
497
// 8. Return. The element won't attempt to load another resource until this algorithm is triggered again.
490
498
return {};
@@ -553,7 +561,7 @@ enum class FetchMode {
553
561
};
554
562
555
563
// https://html.spec.whatwg.org/multipage/media.html#concept-media-load-resource
556
- WebIDL::ExceptionOr<void > HTMLMediaElement::fetch_resource (AK::URL const & url_record, Function<void ()> failure_callback)
564
+ WebIDL::ExceptionOr<void > HTMLMediaElement::fetch_resource (AK::URL const & url_record, Function<void (String )> failure_callback)
557
565
{
558
566
auto & realm = this ->realm ();
559
567
auto & vm = realm.vm ();
@@ -623,7 +631,8 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::fetch_resource(AK::URL const& url_re
623
631
// 4. If the result of verifying response given the current media resource and byteRange is false, then abort these steps.
624
632
// NOTE: We do this step before creating the updateMedia task so that we can invoke the failure callback.
625
633
if (!verify_response (response, byte_range)) {
626
- failure_callback ();
634
+ auto error_message = response->network_error_message ().value_or (" Failed to fetch media resource" sv);
635
+ failure_callback (String::from_utf8 (error_message).release_value_but_fixme_should_propagate_errors ());
627
636
return ;
628
637
}
629
638
@@ -718,7 +727,7 @@ bool HTMLMediaElement::verify_response(JS::NonnullGCPtr<Fetch::Infrastructure::R
718
727
}
719
728
720
729
// https://html.spec.whatwg.org/multipage/media.html#media-data-processing-steps-list
721
- WebIDL::ExceptionOr<void > HTMLMediaElement::process_media_data (Function<void ()> failure_callback)
730
+ WebIDL::ExceptionOr<void > HTMLMediaElement::process_media_data (Function<void (String )> failure_callback)
722
731
{
723
732
auto & realm = this ->realm ();
724
733
auto & vm = realm.vm ();
@@ -734,7 +743,7 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::process_media_data(Function<void()>
734
743
m_fetch_controller->stop_fetch ();
735
744
736
745
// 2. Abort this subalgorithm, returning to the resource selection algorithm.
737
- failure_callback ();
746
+ failure_callback (TRY_OR_THROW_OOM (vm, String::from_utf8 (playback_manager. error (). description ())) );
738
747
739
748
return {};
740
749
}
@@ -866,11 +875,13 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::process_media_data(Function<void()>
866
875
}
867
876
868
877
// https://html.spec.whatwg.org/multipage/media.html#dedicated-media-source-failure-steps
869
- WebIDL::ExceptionOr<void > HTMLMediaElement::handle_media_source_failure (Span<JS::NonnullGCPtr<WebIDL::Promise>> promises)
878
+ WebIDL::ExceptionOr<void > HTMLMediaElement::handle_media_source_failure (Span<JS::NonnullGCPtr<WebIDL::Promise>> promises, String error_message )
870
879
{
871
- auto & vm = this ->vm ();
880
+ auto & realm = this ->realm ();
881
+ auto & vm = realm.vm ();
872
882
873
- // FIXME: 1. Set the error attribute to the result of creating a MediaError with MEDIA_ERR_SRC_NOT_SUPPORTED.
883
+ // 1. Set the error attribute to the result of creating a MediaError with MEDIA_ERR_SRC_NOT_SUPPORTED.
884
+ m_error = TRY (vm.heap ().allocate <MediaError>(realm, realm, MediaError::Code::SrcNotSupported, move (error_message)));
874
885
875
886
// 2. Forget the media element's media-resource-specific tracks.
876
887
forget_media_resource_specific_tracks ();
@@ -882,7 +893,7 @@ WebIDL::ExceptionOr<void> HTMLMediaElement::handle_media_source_failure(Span<JS:
882
893
set_show_poster (true );
883
894
884
895
// 5. Fire an event named error at the media element.
885
- dispatch_event (TRY (DOM::Event::create (realm () , HTML::EventNames::error)));
896
+ dispatch_event (TRY (DOM::Event::create (realm, HTML::EventNames::error)));
886
897
887
898
// 6. Reject pending play promises with promises and a "NotSupportedError" DOMException.
888
899
reject_pending_play_promises<WebIDL::NotSupportedError>(promises, TRY_OR_THROW_OOM (vm, " Media is not supported" _fly_string));
0 commit comments