Split handle_player_event into smaller functions (#37113)

Split HTMLMediaElement::handle_player_event into smaller functions
(#37109)

As requested, I also did a quick pass over the entire file looking for
if/else blocks that could be converted into early returns, but only
found two. Both of those have been changed here.

Testing: This doesn't require (new) tests because it is a reorganization
of existing code.
Fixes: #37109: HTMLMediaElement::handle_player_event is too big

---------

Signed-off-by: Michael Rees <mrees@noeontheend.com>
This commit is contained in:
Michael Rees 2025-06-01 07:49:09 -05:00 committed by GitHub
parent 568d24d4e3
commit 280b34bbd8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1514,60 +1514,67 @@ impl HTMLMediaElement {
} }
} }
fn handle_player_event(&self, event: &PlayerEvent, can_gc: CanGc) { fn end_of_playback_in_forwards_direction(&self) {
match *event { // Step 1. If the media element has a loop attribute specified, then seek to the earliest
PlayerEvent::EndOfStream => { // posible position of the media resource and return.
// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list
// => "If the media data can be fetched but is found by inspection to be in
// an unsupported format, or can otherwise not be rendered at all"
if self.ready_state.get() < ReadyState::HaveMetadata {
self.queue_dedicated_media_source_failure_steps();
} else {
// https://html.spec.whatwg.org/multipage/#reaches-the-end
match self.direction_of_playback() {
PlaybackDirection::Forwards => {
// Step 1.
if self.Loop() { if self.Loop() {
self.seek( self.seek(
self.earliest_possible_position(), self.earliest_possible_position(),
/* approximate_for_speed*/ false, /* approximate_for_speed*/ false,
); );
} else { return;
// Step 2. }
// Step 2. The ended IDL attribute starts returning true once the event loop returns to
// step 1.
// The **ended playback** condition is implemented inside of // The **ended playback** condition is implemented inside of
// the HTMLMediaElementMethods::Ended method // the HTMLMediaElementMethods::Ended method
// Step 3. // Step 3. Queue a media element task given the media element and the following steps:
let this = Trusted::new(self); let this = Trusted::new(self);
self.owner_global().task_manager().media_element_task_source().queue( self.owner_global()
task!(reaches_the_end_steps: move || { .task_manager()
.media_element_task_source()
.queue(task!(reaches_the_end_steps: move || {
let this = this.root(); let this = this.root();
// Step 3.1. // Step 3.1. Fire an event named timeupdate at the media element
this.upcast::<EventTarget>().fire_event(atom!("timeupdate"), CanGc::note()); this.upcast::<EventTarget>().fire_event(atom!("timeupdate"), CanGc::note());
// Step 3.2. // Step 3.2. If the media element has ended playback, the direction of playback is
// forwards, and paused is false, then:
if this.Ended() && !this.Paused() { if this.Ended() && !this.Paused() {
// Step 3.2.1. // Step 3.2.1. Set the paused attribute to true
this.paused.set(true); this.paused.set(true);
// Step 3.2.2. // Step 3.2.2. Fire an event named pause at the media element
this.upcast::<EventTarget>().fire_event(atom!("pause"), CanGc::note()); this.upcast::<EventTarget>().fire_event(atom!("pause"), CanGc::note());
// Step 3.2.3. // Step 3.2.3. Take pending play promises and reject pending play promises with
// the result and an "AbortError" DOMException
this.take_pending_play_promises(Err(Error::Abort)); this.take_pending_play_promises(Err(Error::Abort));
this.fulfill_in_flight_play_promises(|| ()); this.fulfill_in_flight_play_promises(|| ());
} }
// Step 3.3. // Step 3.3. Fire an event named ended at the media element.
this.upcast::<EventTarget>().fire_event(atom!("ended"), CanGc::note()); this.upcast::<EventTarget>().fire_event(atom!("ended"), CanGc::note());
}) }));
);
// https://html.spec.whatwg.org/multipage/#dom-media-have_current_data // https://html.spec.whatwg.org/multipage/#dom-media-have_current_data
self.change_ready_state(ReadyState::HaveCurrentData); self.change_ready_state(ReadyState::HaveCurrentData);
} }
},
fn playback_end(&self) {
// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list
// => "If the media data can be fetched but is found by inspection to be in
// an unsupported format, or can otherwise not be rendered at all"
if self.ready_state.get() < ReadyState::HaveMetadata {
self.queue_dedicated_media_source_failure_steps();
return;
}
// https://html.spec.whatwg.org/multipage/#reaches-the-end
match self.direction_of_playback() {
PlaybackDirection::Forwards => self.end_of_playback_in_forwards_direction(),
PlaybackDirection::Backwards => { PlaybackDirection::Backwards => {
if self.playback_position.get() <= self.earliest_possible_position() { if self.playback_position.get() <= self.earliest_possible_position() {
@ -1579,8 +1586,8 @@ impl HTMLMediaElement {
}, },
} }
} }
},
PlayerEvent::Error(ref error) => { fn playback_error(&self, error: &str, can_gc: CanGc) {
error!("Player error: {:?}", error); error!("Player error: {:?}", error);
// If we have already flagged an error condition while processing // If we have already flagged an error condition while processing
@ -1592,9 +1599,7 @@ impl HTMLMediaElement {
// https://html.spec.whatwg.org/multipage/#loading-the-media-resource:media-data-13 // https://html.spec.whatwg.org/multipage/#loading-the-media-resource:media-data-13
// 1. The user agent should cancel the fetching process. // 1. The user agent should cancel the fetching process.
if let Some(ref mut current_fetch_context) = if let Some(ref mut current_fetch_context) = *self.current_fetch_context.borrow_mut() {
*self.current_fetch_context.borrow_mut()
{
current_fetch_context.cancel(CancelReason::Error); current_fetch_context.cancel(CancelReason::Error);
} }
// 2. Set the error attribute to the result of creating a MediaError with MEDIA_ERR_DECODE. // 2. Set the error attribute to the result of creating a MediaError with MEDIA_ERR_DECODE.
@ -1615,14 +1620,13 @@ impl HTMLMediaElement {
.fire_event(atom!("error"), can_gc); .fire_event(atom!("error"), can_gc);
// TODO: 6. Abort the overall resource selection algorithm. // TODO: 6. Abort the overall resource selection algorithm.
},
PlayerEvent::VideoFrameUpdated => {
// Check if the frame was resized
if let Some(frame) = self.video_renderer.lock().unwrap().current_frame {
self.handle_resize(Some(frame.width as u32), Some(frame.height as u32));
} }
},
PlayerEvent::MetadataUpdated(ref metadata) => { fn playback_metadata_updated(
&self,
metadata: &servo_media::player::metadata::Metadata,
can_gc: CanGc,
) {
// https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list
// => If the media resource is found to have an audio track // => If the media resource is found to have an audio track
if !metadata.audio_tracks.is_empty() { if !metadata.audio_tracks.is_empty() {
@ -1818,8 +1822,16 @@ impl HTMLMediaElement {
.clone() .clone()
.unwrap_or(window.get_url().into_string()), .unwrap_or(window.get_url().into_string()),
); );
}, }
PlayerEvent::NeedData => {
fn playback_video_frame_updated(&self) {
// Check if the frame was resized
if let Some(frame) = self.video_renderer.lock().unwrap().current_frame {
self.handle_resize(Some(frame.width as u32), Some(frame.height as u32));
}
}
fn playback_need_data(&self) {
// The player needs more data. // The player needs more data.
// If we already have a valid fetch request, we do nothing. // If we already have a valid fetch request, we do nothing.
// Otherwise, if we have no request and the previous request was // Otherwise, if we have no request and the previous request was
@ -1838,23 +1850,23 @@ impl HTMLMediaElement {
_ => (), _ => (),
} }
} }
}, }
PlayerEvent::EnoughData => {
fn playback_enough_data(&self) {
self.change_ready_state(ReadyState::HaveEnoughData); self.change_ready_state(ReadyState::HaveEnoughData);
// The player has enough data and it is asking us to stop pushing // The player has enough data and it is asking us to stop pushing
// bytes, so we cancel the ongoing fetch request iff we are able // bytes, so we cancel the ongoing fetch request iff we are able
// to restart it from where we left. Otherwise, we continue the // to restart it from where we left. Otherwise, we continue the
// current fetch request, assuming that some frames will be dropped. // current fetch request, assuming that some frames will be dropped.
if let Some(ref mut current_fetch_context) = if let Some(ref mut current_fetch_context) = *self.current_fetch_context.borrow_mut() {
*self.current_fetch_context.borrow_mut()
{
if current_fetch_context.is_seekable() { if current_fetch_context.is_seekable() {
current_fetch_context.cancel(CancelReason::Backoff); current_fetch_context.cancel(CancelReason::Backoff);
} }
} }
}, }
PlayerEvent::PositionChanged(position) => {
fn playback_position_changed(&self, position: u64) {
let position = position as f64; let position = position as f64;
let _ = self let _ = self
.played .played
@ -1868,14 +1880,10 @@ impl HTMLMediaElement {
"Sending media session event set position state {:?}", "Sending media session event set position state {:?}",
media_position_state media_position_state
); );
self.send_media_session_event(MediaSessionEvent::SetPositionState( self.send_media_session_event(MediaSessionEvent::SetPositionState(media_position_state));
media_position_state, }
));
}, fn playback_seek_done(&self) {
PlayerEvent::SeekData(p, ref seek_lock) => {
self.fetch_request(Some(p), Some(seek_lock.clone()));
},
PlayerEvent::SeekDone(_) => {
// Continuation of // Continuation of
// https://html.spec.whatwg.org/multipage/#dom-media-seek // https://html.spec.whatwg.org/multipage/#dom-media-seek
@ -1885,8 +1893,9 @@ impl HTMLMediaElement {
generation_id: self.generation_id.get(), generation_id: self.generation_id.get(),
}; };
ScriptThread::await_stable_state(Microtask::MediaElement(task)); ScriptThread::await_stable_state(Microtask::MediaElement(task));
}, }
PlayerEvent::StateChanged(ref state) => {
fn playback_state_changed(&self, state: &PlaybackState) {
let mut media_session_playback_state = MediaSessionPlaybackState::None_; let mut media_session_playback_state = MediaSessionPlaybackState::None_;
match *state { match *state {
PlaybackState::Paused => { PlaybackState::Paused => {
@ -1913,7 +1922,24 @@ impl HTMLMediaElement {
self.send_media_session_event(MediaSessionEvent::PlaybackStateChange( self.send_media_session_event(MediaSessionEvent::PlaybackStateChange(
media_session_playback_state, media_session_playback_state,
)); ));
}
fn handle_player_event(&self, event: &PlayerEvent, can_gc: CanGc) {
match *event {
PlayerEvent::EndOfStream => self.playback_end(),
PlayerEvent::Error(ref error) => self.playback_error(error, can_gc),
PlayerEvent::VideoFrameUpdated => self.playback_video_frame_updated(),
PlayerEvent::MetadataUpdated(ref metadata) => {
self.playback_metadata_updated(metadata, can_gc)
}, },
PlayerEvent::NeedData => self.playback_need_data(),
PlayerEvent::EnoughData => self.playback_enough_data(),
PlayerEvent::PositionChanged(position) => self.playback_position_changed(position),
PlayerEvent::SeekData(p, ref seek_lock) => {
self.fetch_request(Some(p), Some(seek_lock.clone()));
},
PlayerEvent::SeekDone(_) => self.playback_seek_done(),
PlayerEvent::StateChanged(ref state) => self.playback_state_changed(state),
} }
} }