mirror of
https://github.com/servo/servo.git
synced 2025-08-11 16:35:33 +01:00
htmlvideoelement: Fix poster frame processing algorithm (#37533)
According to HTML specification the poster attribute determines the element's poster frame (regardless of the value of the element's show poster flag). https://html.spec.whatwg.org/multipage/#poster-frame So the poster frame and the show poster flag is orthogonal to each other, the latest one only controls when browser should display the poster frame and should do not block accepting video frames from media pipeline (e.g. on new_preroll callback from video sink). During layout the video element should select the current frame which will be presented based on first matching condition from the list: https://html.spec.whatwg.org/multipage/#the-video-element:the-video-element-7 Testing: Improvements in the following WPT tests - html/canvas/element/manual/imagebitmap/createImageBitmap* - html/semantics/embedded-content/the-canvas-element/* Fixes: #37165 --------- Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com> Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
d0100797e8
commit
06b5422abf
8 changed files with 70 additions and 112 deletions
|
@ -170,7 +170,8 @@ pub(crate) struct MediaFrameRenderer {
|
|||
old_frame: Option<ImageKey>,
|
||||
very_old_frame: Option<ImageKey>,
|
||||
current_frame_holder: Option<FrameHolder>,
|
||||
show_poster: bool,
|
||||
/// <https://html.spec.whatwg.org/multipage/#poster-frame>
|
||||
poster_frame: Option<MediaFrame>,
|
||||
}
|
||||
|
||||
impl MediaFrameRenderer {
|
||||
|
@ -182,29 +183,23 @@ impl MediaFrameRenderer {
|
|||
old_frame: None,
|
||||
very_old_frame: None,
|
||||
current_frame_holder: None,
|
||||
show_poster: false,
|
||||
poster_frame: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn render_poster_frame(&mut self, image: Arc<RasterImage>) {
|
||||
if let Some(image_key) = image.id {
|
||||
self.current_frame = Some(MediaFrame {
|
||||
fn set_poster_frame(&mut self, image: Option<Arc<RasterImage>>) {
|
||||
self.poster_frame = image.and_then(|image| {
|
||||
image.id.map(|image_key| MediaFrame {
|
||||
image_key,
|
||||
width: image.metadata.width as i32,
|
||||
height: image.metadata.height as i32,
|
||||
});
|
||||
self.show_poster = true;
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl VideoFrameRenderer for MediaFrameRenderer {
|
||||
fn render(&mut self, frame: VideoFrame) {
|
||||
// Don't render new frames if the poster should be shown
|
||||
if self.show_poster {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut updates = vec![];
|
||||
|
||||
if let Some(old_image_key) = mem::replace(&mut self.very_old_frame, self.old_frame.take()) {
|
||||
|
@ -730,7 +725,7 @@ impl HTMLMediaElement {
|
|||
self.paused.set(false);
|
||||
// Step 2
|
||||
if self.show_poster.get() {
|
||||
self.set_show_poster(false);
|
||||
self.show_poster.set(false);
|
||||
self.time_marches_on();
|
||||
}
|
||||
// Step 3
|
||||
|
@ -753,7 +748,7 @@ impl HTMLMediaElement {
|
|||
self.network_state.set(NetworkState::NoSource);
|
||||
|
||||
// Step 2.
|
||||
self.set_show_poster(true);
|
||||
self.show_poster.set(true);
|
||||
|
||||
// Step 3.
|
||||
self.delay_load_event(true, can_gc);
|
||||
|
@ -1081,7 +1076,7 @@ impl HTMLMediaElement {
|
|||
this.network_state.set(NetworkState::NoSource);
|
||||
|
||||
// Step 4.
|
||||
this.set_show_poster(true);
|
||||
this.show_poster.set(true);
|
||||
|
||||
// Step 5.
|
||||
this.upcast::<EventTarget>().fire_event(atom!("error"), CanGc::note());
|
||||
|
@ -1198,8 +1193,8 @@ impl HTMLMediaElement {
|
|||
self.fulfill_in_flight_play_promises(|| ());
|
||||
}
|
||||
|
||||
// Step 6.7.
|
||||
if !self.seeking.get() {
|
||||
// Step 6.7. If seeking is true, set it to false.
|
||||
if self.seeking.get() {
|
||||
self.seeking.set(false);
|
||||
}
|
||||
|
||||
|
@ -1298,7 +1293,7 @@ impl HTMLMediaElement {
|
|||
// https://html.spec.whatwg.org/multipage/#dom-media-seek
|
||||
fn seek(&self, time: f64, _approximate_for_speed: bool) {
|
||||
// Step 1.
|
||||
self.set_show_poster(false);
|
||||
self.show_poster.set(false);
|
||||
|
||||
// Step 2.
|
||||
if self.ready_state.get() == ReadyState::HaveNothing {
|
||||
|
@ -1403,19 +1398,14 @@ impl HTMLMediaElement {
|
|||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#poster-frame>
|
||||
pub(crate) fn process_poster_image_loaded(&self, image: Arc<RasterImage>) {
|
||||
if !self.show_poster.get() {
|
||||
return;
|
||||
}
|
||||
pub(crate) fn set_poster_frame(&self, image: Option<Arc<RasterImage>>) {
|
||||
let queue_postershown_event = pref!(media_testing_enabled) && image.is_some();
|
||||
|
||||
// Step 6.
|
||||
self.handle_resize(Some(image.metadata.width), Some(image.metadata.height));
|
||||
self.video_renderer
|
||||
.lock()
|
||||
.unwrap()
|
||||
.render_poster_frame(image);
|
||||
self.video_renderer.lock().unwrap().set_poster_frame(image);
|
||||
|
||||
if pref!(media_testing_enabled) {
|
||||
self.upcast::<Node>().dirty(NodeDamage::Other);
|
||||
|
||||
if queue_postershown_event {
|
||||
self.owner_global()
|
||||
.task_manager()
|
||||
.media_element_task_source()
|
||||
|
@ -2097,6 +2087,7 @@ impl HTMLMediaElement {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the video frame at the current playback position.
|
||||
pub(crate) fn get_current_frame(&self) -> Option<VideoFrame> {
|
||||
self.video_renderer
|
||||
.lock()
|
||||
|
@ -2106,8 +2097,21 @@ impl HTMLMediaElement {
|
|||
.map(|holder| holder.get_frame())
|
||||
}
|
||||
|
||||
pub(crate) fn get_current_frame_data(&self) -> Option<MediaFrame> {
|
||||
self.video_renderer.lock().unwrap().current_frame
|
||||
/// Gets the current frame of the video element to present, if any.
|
||||
/// <https://html.spec.whatwg.org/multipage/#the-video-element:the-video-element-7>
|
||||
pub(crate) fn get_current_frame_to_present(&self) -> Option<MediaFrame> {
|
||||
let (current_frame, poster_frame) = {
|
||||
let renderer = self.video_renderer.lock().unwrap();
|
||||
(renderer.current_frame, renderer.poster_frame)
|
||||
};
|
||||
|
||||
// If the show poster flag is set (or there is no current video frame to
|
||||
// present) AND there is a poster frame, present that.
|
||||
if (self.show_poster.get() || current_frame.is_none()) && poster_frame.is_some() {
|
||||
return poster_frame;
|
||||
}
|
||||
|
||||
current_frame
|
||||
}
|
||||
|
||||
pub(crate) fn clear_current_frame_data(&self) {
|
||||
|
@ -2153,13 +2157,6 @@ impl HTMLMediaElement {
|
|||
self.duration.set(duration);
|
||||
}
|
||||
|
||||
/// Sets a new value for the show_poster propperty. Updates video_rederer
|
||||
/// with the new value.
|
||||
pub(crate) fn set_show_poster(&self, show_poster: bool) {
|
||||
self.show_poster.set(show_poster);
|
||||
self.video_renderer.lock().unwrap().show_poster = show_poster;
|
||||
}
|
||||
|
||||
pub(crate) fn reset(&self) {
|
||||
if let Some(ref player) = *self.player.borrow() {
|
||||
if let Err(e) = player.lock().unwrap().stop() {
|
||||
|
@ -2378,7 +2375,7 @@ impl HTMLMediaElementMethods<crate::DomTypeHolder> for HTMLMediaElement {
|
|||
|
||||
// Step 6.2.
|
||||
if self.show_poster.get() {
|
||||
self.set_show_poster(false);
|
||||
self.show_poster.set(false);
|
||||
self.time_marches_on();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue