From 2db141fb8b7c941d77ffa0ff32b872679b55ea2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 17 Oct 2018 16:16:21 +0200 Subject: [PATCH 1/8] Setter and getter for HTMLMediaElement.currentTime --- components/script/dom/htmlmediaelement.rs | 61 +++++++++++++++++-- .../dom/webidls/HTMLMediaElement.webidl | 2 +- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 8aad0820502..f594608563c 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -16,6 +16,7 @@ use dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId}; use dom::bindings::codegen::InheritTypes::{HTMLMediaElementTypeId, NodeTypeId}; use dom::bindings::error::{Error, ErrorResult}; use dom::bindings::inheritance::Castable; +use dom::bindings::num::Finite; use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::DomObject; use dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom}; @@ -161,7 +162,7 @@ pub struct HTMLMediaElement { #[ignore_malloc_size_of = "promises are hard"] in_flight_play_promises_queue: DomRefCell]>, ErrorResult)>>, #[ignore_malloc_size_of = "servo_media"] - player: Box>, + player: Box>, #[ignore_malloc_size_of = "Arc"] frame_renderer: Arc>, fetch_canceller: DomRefCell, @@ -169,6 +170,10 @@ pub struct HTMLMediaElement { show_poster: Cell, /// https://html.spec.whatwg.org/multipage/#dom-media-duration duration: Cell, + /// https://html.spec.whatwg.org/multipage/media.html#official-playback-position + playback_position: Cell, + /// https://html.spec.whatwg.org/multipage/media.html#default-playback-start-position + default_playback_start_position: Cell, } /// @@ -216,6 +221,8 @@ impl HTMLMediaElement { fetch_canceller: DomRefCell::new(Default::default()), show_poster: Cell::new(true), duration: Cell::new(f64::NAN), + playback_position: Cell::new(0.), + default_playback_start_position: Cell::new(0.), } } @@ -961,8 +968,12 @@ impl HTMLMediaElement { self.media_element_load_algorithm(); } - // servo media player - fn setup_media_player(&self) -> Result<(), ServoMediaError>{ + // https://html.spec.whatwg.org/multipage/#dom-media-seek + fn seek(&self, _time: f64, _approximate_for_speed: bool) { + // XXX + } + + fn setup_media_player(&self) -> Result<(), ServoMediaError> { let (action_sender, action_receiver) = ipc::channel().unwrap(); self.player.register_event_handler(action_sender)?; @@ -1004,8 +1015,7 @@ impl HTMLMediaElement { // XXX(ferjm) Update the timeline offset. // Step 3. - // XXX(ferjm) Set the current and official playback positions - // to the earliest possible position. + self.playback_position.set(0.); // Step 4. if let Some(duration) = metadata.duration { @@ -1028,7 +1038,27 @@ impl HTMLMediaElement { // Step 6. self.change_ready_state(ReadyState::HaveMetadata); - // XXX(ferjm) Steps 7 to 13. + // Step 7. + let mut _jumped = false; + + // Step 8. + if self.default_playback_start_position.get() > 0. { + self.seek(self.default_playback_start_position.get(), /* approximate_for_speed*/ false); + _jumped = true; + } + + // Step 9. + self.default_playback_start_position.set(0.); + + // Steps 10 and 11. + // XXX(ferjm) Implement parser for + // https://www.w3.org/TR/media-frags/#media-fragment-syntax + // https://github.com/servo/media/issues/156 + + // XXX Steps 12 and 13 require audio and video tracks support. + }, + PlayerEvent::PositionChanged(position) => { + self.playback_position.set(position as f64); }, PlayerEvent::StateChanged(ref state) => match *state { PlaybackState::Paused => { @@ -1157,6 +1187,25 @@ impl HTMLMediaElementMethods for HTMLMediaElement { fn Duration(&self) -> f64 { self.duration.get() } + + // https://html.spec.whatwg.org/multipage/#dom-media-currenttime + fn CurrentTime(&self) -> Finite { + Finite::wrap(if self.default_playback_start_position.get() != 0. { + self.default_playback_start_position.get() + } else { + self.playback_position.get() + }) + } + + // https://html.spec.whatwg.org/multipage/#dom-media-currenttime + fn SetCurrentTime(&self, time: Finite) { + if self.ready_state.get() == ReadyState::HaveNothing { + self.default_playback_start_position.set(*time); + } else { + self.playback_position.set(*time); + self.seek(*time, /* approximate_for_speed */ false); + } + } } impl VirtualMethods for HTMLMediaElement { diff --git a/components/script/dom/webidls/HTMLMediaElement.webidl b/components/script/dom/webidls/HTMLMediaElement.webidl index e00b1de7c4f..a8b9241c54d 100644 --- a/components/script/dom/webidls/HTMLMediaElement.webidl +++ b/components/script/dom/webidls/HTMLMediaElement.webidl @@ -37,7 +37,7 @@ interface HTMLMediaElement : HTMLElement { // readonly attribute boolean seeking; // playback state - // attribute double currentTime; + attribute double currentTime; // void fastSeek(double time); readonly attribute unrestricted double duration; // Date getStartDate(); From 75407822bc6840da508ccf5cd80d0115ee91d2aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Mon, 22 Oct 2018 16:01:00 +0200 Subject: [PATCH 2/8] HTMLMediaElement seeking --- Cargo.lock | 24 ++-- Cargo.toml | 2 + components/atoms/static_atoms.txt | 2 + components/script/dom/htmlmediaelement.rs | 111 +++++++++++++++++- .../dom/webidls/HTMLMediaElement.webidl | 4 +- 5 files changed, 124 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c0f09bcdc5..4cbee3861f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3025,7 +3025,7 @@ dependencies = [ "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "servo-media 0.1.0 (git+https://github.com/servo/media)", + "servo-media 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", "servo_allocator 0.0.1", "servo_arc 0.1.1", "servo_atoms 0.0.1", @@ -3261,9 +3261,9 @@ name = "servo-media" version = "0.1.0" source = "git+https://github.com/servo/media#3b347d7b0431c58611e2bd7b22d34062b64cda26" dependencies = [ - "servo-media-audio 0.1.0 (git+https://github.com/servo/media)", - "servo-media-gstreamer 0.1.0 (git+https://github.com/servo/media)", - "servo-media-player 0.1.0 (git+https://github.com/servo/media)", + "servo-media-audio 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", + "servo-media-gstreamer 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", + "servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", ] [[package]] @@ -3279,7 +3279,7 @@ dependencies = [ "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "servo_media_derive 0.1.0 (git+https://github.com/servo/media)", + "servo_media_derive 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3296,8 +3296,8 @@ dependencies = [ "gstreamer-player 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "servo-media-audio 0.1.0 (git+https://github.com/servo/media)", - "servo-media-player 0.1.0 (git+https://github.com/servo/media)", + "servo-media-audio 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", + "servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", "zip 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4586,12 +4586,12 @@ dependencies = [ "checksum servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93f799b649b4a2bf362398910eca35240704c7e765e780349b2bb1070d892262" "checksum servo-fontconfig-sys 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b46d201addcfbd25c1798ad1281d98c40743824e0b0f1e611bd3d5d0d31a7b8d" "checksum servo-freetype-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d00ab791f66cd2ec58e72c91b6076cee20fac560463aa871404eb31dfc9c4ff" -"checksum servo-media 0.1.0 (git+https://github.com/servo/media)" = "" -"checksum servo-media-audio 0.1.0 (git+https://github.com/servo/media)" = "" -"checksum servo-media-gstreamer 0.1.0 (git+https://github.com/servo/media)" = "" -"checksum servo-media-player 0.1.0 (git+https://github.com/servo/media)" = "" +"checksum servo-media 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" +"checksum servo-media-audio 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" +"checksum servo-media-gstreamer 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" +"checksum servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" "checksum servo-skia 0.30000019.1 (registry+https://github.com/rust-lang/crates.io-index)" = "82eddddcf9512dd7c60eccdb486e60e5bd4930afaa4da2d7d4afdff75950fb88" -"checksum servo_media_derive 0.1.0 (git+https://github.com/servo/media)" = "" +"checksum servo_media_derive 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" "checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" "checksum shared_library 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8254bf098ce4d8d7cc7cc6de438c5488adc5297e5b7ffef88816c0a91bd289c1" "checksum sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6649e43c1a1e68d29ed56d0dc3b5b6cf3b901da77cf107c4066b9e3da036df5" diff --git a/Cargo.toml b/Cargo.toml index bb452af5fa6..93aa92630cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,5 @@ opt-level = 3 # # [patch."https://github.com/servo/"] # = { path = "/path/to/local/checkout" } +[patch."https://github.com/servo/media"] +servo-media = { git = "https://github.com/ferjm/media", branch = "seek" } diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt index f123a2b66c5..d3e7bf26f11 100644 --- a/components/atoms/static_atoms.txt +++ b/components/atoms/static_atoms.txt @@ -74,6 +74,8 @@ scan screen scroll-position search +seeked +seeking select serif statechange diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index f594608563c..0f67d7a6fd2 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -170,10 +170,12 @@ pub struct HTMLMediaElement { show_poster: Cell, /// https://html.spec.whatwg.org/multipage/#dom-media-duration duration: Cell, - /// https://html.spec.whatwg.org/multipage/media.html#official-playback-position + /// https://html.spec.whatwg.org/multipage/#official-playback-position playback_position: Cell, - /// https://html.spec.whatwg.org/multipage/media.html#default-playback-start-position + /// https://html.spec.whatwg.org/multipage/#default-playback-start-position default_playback_start_position: Cell, + /// https://html.spec.whatwg.org/multipage/#dom-media-seeking + seeking: Cell, } /// @@ -223,6 +225,7 @@ impl HTMLMediaElement { duration: Cell::new(f64::NAN), playback_position: Cell::new(0.), default_playback_start_position: Cell::new(0.), + seeking: Cell::new(false), } } @@ -969,8 +972,69 @@ impl HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#dom-media-seek - fn seek(&self, _time: f64, _approximate_for_speed: bool) { - // XXX + fn seek(&self, time: f64, approximate_for_speed: bool) { + // Step 1. + self.show_poster.set(false); + + // Step 2. + if self.ready_state.get() == ReadyState::HaveNothing { + return; + } + + // Step 3. + if self.seeking.get() { + // This will cancel only the sync part of the seek algorithm. + self.generation_id.set(self.generation_id.get() + 1); + } + + // Step 4. + // The flag will be cleared when the media engine tells us the seek was done. + self.seeking.set(true); + + // Step 5. + // XXX(ferjm) The rest of the steps should be run in parallel, so seeking cancelation + // can be done properly. No other browser does it yet anyway. + + // Step 6. + let time = f64::min(time, self.Duration()); + + // Step 7. + let time = f64::max(time, 0.); + + // Step 8. + // XXX(ferjm) seekable attribute. + + // Step 9. + let accurate = !approximate_for_speed; + + // Step 10. + let window = window_from_node(self); + let task_source = window.media_element_task_source(); + task_source.queue_simple_event(self.upcast(), atom!("seeking"), &window); + + // Step 11. + // XXX self.player.seek(time, accurate); + + // The rest of the steps are handled when the media engine signals a + // ready state change or otherwise satisfies seek completion and signals + // a position change. + } + + // https://html.spec.whatwg.org/multipage/#dom-media-seek + fn seek_sync(&self) { + // Step 14. + self.seeking.set(false); + + // Step 15. + self.time_marches_on(); + + // Step 16. + let window = window_from_node(self); + let task_source = window.media_element_task_source(); + task_source.queue_simple_event(self.upcast(), atom!("timeupdate"), &window); + + // Step 17. + task_source.queue_simple_event(self.upcast(), atom!("seeked"), &window); } fn setup_media_player(&self) -> Result<(), ServoMediaError> { @@ -1043,7 +1107,10 @@ impl HTMLMediaElement { // Step 8. if self.default_playback_start_position.get() > 0. { - self.seek(self.default_playback_start_position.get(), /* approximate_for_speed*/ false); + self.seek( + self.default_playback_start_position.get(), + /* approximate_for_speed*/ false, + ); _jumped = true; } @@ -1084,6 +1151,20 @@ impl HTMLMediaElement { PlayerEvent::FrameUpdated => { self.upcast::().dirty(NodeDamage::OtherNodeDamage); }, + PlayerEvent::SeekData(_) => { + // XXX byte-range request + }, + PlayerEvent::SeekDone(_) => { + // Continuation of + // https://html.spec.whatwg.org/multipage/#dom-media-seek + + // Step 13. + let task = MediaElementMicrotask::SeekedTask { + elem: DomRoot::from_ref(self), + generation_id: self.generation_id.get(), + }; + ScriptThread::await_stable_state(Microtask::MediaElement(task)); + }, PlayerEvent::Error => { self.error.set(Some(&*MediaError::new( &*window_from_node(self), @@ -1206,6 +1287,14 @@ impl HTMLMediaElementMethods for HTMLMediaElement { self.seek(*time, /* approximate_for_speed */ false); } } + + fn Seeking(&self) -> bool { + self.seeking.get() + } + + fn FastSeek(&self, time: Finite) { + self.seek(*time, /* approximat_for_speed */ true); + } } impl VirtualMethods for HTMLMediaElement { @@ -1263,6 +1352,10 @@ pub enum MediaElementMicrotask { PauseIfNotInDocumentTask { elem: DomRoot, }, + SeekedTask { + elem: DomRoot, + generation_id: u32, + }, } impl MicrotaskRunnable for MediaElementMicrotask { @@ -1282,6 +1375,14 @@ impl MicrotaskRunnable for MediaElementMicrotask { elem.internal_pause_steps(); } }, + &MediaElementMicrotask::SeekedTask { + ref elem, + generation_id, + } => { + if generation_id == elem.generation_id.get() { + elem.seek_sync(); + } + }, } } } diff --git a/components/script/dom/webidls/HTMLMediaElement.webidl b/components/script/dom/webidls/HTMLMediaElement.webidl index a8b9241c54d..f258f1ffb83 100644 --- a/components/script/dom/webidls/HTMLMediaElement.webidl +++ b/components/script/dom/webidls/HTMLMediaElement.webidl @@ -34,11 +34,11 @@ interface HTMLMediaElement : HTMLElement { const unsigned short HAVE_FUTURE_DATA = 3; const unsigned short HAVE_ENOUGH_DATA = 4; readonly attribute unsigned short readyState; - // readonly attribute boolean seeking; + readonly attribute boolean seeking; // playback state attribute double currentTime; - // void fastSeek(double time); + void fastSeek(double time); readonly attribute unrestricted double duration; // Date getStartDate(); readonly attribute boolean paused; From 44133bfb3c79da2d5ec814102f4d0a0bee55c54b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 23 Oct 2018 17:01:39 +0200 Subject: [PATCH 3/8] Byte range request for HTMLMediaElement seeking --- Cargo.lock | 24 +-- Cargo.toml | 2 - components/script/dom/htmlmediaelement.rs | 170 +++++++++++++++------- 3 files changed, 130 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4cbee3861f7..3c0f09bcdc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3025,7 +3025,7 @@ dependencies = [ "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "servo-media 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", + "servo-media 0.1.0 (git+https://github.com/servo/media)", "servo_allocator 0.0.1", "servo_arc 0.1.1", "servo_atoms 0.0.1", @@ -3261,9 +3261,9 @@ name = "servo-media" version = "0.1.0" source = "git+https://github.com/servo/media#3b347d7b0431c58611e2bd7b22d34062b64cda26" dependencies = [ - "servo-media-audio 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", - "servo-media-gstreamer 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", - "servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", + "servo-media-audio 0.1.0 (git+https://github.com/servo/media)", + "servo-media-gstreamer 0.1.0 (git+https://github.com/servo/media)", + "servo-media-player 0.1.0 (git+https://github.com/servo/media)", ] [[package]] @@ -3279,7 +3279,7 @@ dependencies = [ "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "servo_media_derive 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", + "servo_media_derive 0.1.0 (git+https://github.com/servo/media)", "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3296,8 +3296,8 @@ dependencies = [ "gstreamer-player 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "servo-media-audio 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", - "servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=seek)", + "servo-media-audio 0.1.0 (git+https://github.com/servo/media)", + "servo-media-player 0.1.0 (git+https://github.com/servo/media)", "zip 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4586,12 +4586,12 @@ dependencies = [ "checksum servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93f799b649b4a2bf362398910eca35240704c7e765e780349b2bb1070d892262" "checksum servo-fontconfig-sys 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b46d201addcfbd25c1798ad1281d98c40743824e0b0f1e611bd3d5d0d31a7b8d" "checksum servo-freetype-sys 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d00ab791f66cd2ec58e72c91b6076cee20fac560463aa871404eb31dfc9c4ff" -"checksum servo-media 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" -"checksum servo-media-audio 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" -"checksum servo-media-gstreamer 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" -"checksum servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" +"checksum servo-media 0.1.0 (git+https://github.com/servo/media)" = "" +"checksum servo-media-audio 0.1.0 (git+https://github.com/servo/media)" = "" +"checksum servo-media-gstreamer 0.1.0 (git+https://github.com/servo/media)" = "" +"checksum servo-media-player 0.1.0 (git+https://github.com/servo/media)" = "" "checksum servo-skia 0.30000019.1 (registry+https://github.com/rust-lang/crates.io-index)" = "82eddddcf9512dd7c60eccdb486e60e5bd4930afaa4da2d7d4afdff75950fb88" -"checksum servo_media_derive 0.1.0 (git+https://github.com/ferjm/media?branch=seek)" = "" +"checksum servo_media_derive 0.1.0 (git+https://github.com/servo/media)" = "" "checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" "checksum shared_library 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8254bf098ce4d8d7cc7cc6de438c5488adc5297e5b7ffef88816c0a91bd289c1" "checksum sig 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c6649e43c1a1e68d29ed56d0dc3b5b6cf3b901da77cf107c4066b9e3da036df5" diff --git a/Cargo.toml b/Cargo.toml index 93aa92630cd..bb452af5fa6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,5 +22,3 @@ opt-level = 3 # # [patch."https://github.com/servo/"] # = { path = "/path/to/local/checkout" } -[patch."https://github.com/servo/media"] -servo-media = { git = "https://github.com/ferjm/media", branch = "seek" } diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 0f67d7a6fd2..baf5607ef2b 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -35,7 +35,7 @@ use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use fetch::FetchCanceller; use html5ever::{LocalName, Prefix}; -use hyper::header::ContentLength; +use hyper::header::{AcceptRanges, ByteRangeSpec, ContentLength, Headers, Range as HyperRange, RangeUnit}; use ipc_channel::ipc; use ipc_channel::router::ROUTER; use microtask::{Microtask, MicrotaskRunnable}; @@ -48,7 +48,7 @@ use script_layout_interface::HTMLMediaData; use script_thread::ScriptThread; use servo_media::Error as ServoMediaError; use servo_media::ServoMedia; -use servo_media::player::{PlaybackState, Player, PlayerEvent}; +use servo_media::player::{PlaybackState, Player, PlayerEvent, StreamType}; use servo_media::player::frame::{Frame, FrameRenderer}; use servo_url::ServoUrl; use std::cell::Cell; @@ -176,6 +176,15 @@ pub struct HTMLMediaElement { default_playback_start_position: Cell, /// https://html.spec.whatwg.org/multipage/#dom-media-seeking seeking: Cell, + /// Tells wether the current stream is seekable or not. + /// XXX(ferjm) This will eventually be changed by a TimeRange. + /// For now, we only consider a stream seekable if the server + /// supports byte-range requests. This should eventually change to + /// allow seeking to buffered content as well, even if the server + /// does not support byte-range requests. + seekable: Cell, + /// URL of the media resource, if any. + resource_url: DomRefCell>, } /// @@ -226,6 +235,8 @@ impl HTMLMediaElement { playback_position: Cell::new(0.), default_playback_start_position: Cell::new(0.), seeking: Cell::new(false), + seekable: Cell::new(false), + resource_url: DomRefCell::new(None), } } @@ -670,6 +681,65 @@ impl HTMLMediaElement { } } + fn fetch_request(&self, offset: Option) { + if self.resource_url.borrow().is_none() { + eprintln!("Missing request url"); + self.queue_dedicated_media_source_failure_steps(); + return; + } + + // FIXME(nox): Handle CORS setting from crossorigin attribute. + let document = document_from_node(self); + let destination = match self.media_type_id() { + HTMLMediaElementTypeId::HTMLAudioElement => Destination::Audio, + HTMLMediaElementTypeId::HTMLVideoElement => Destination::Video, + }; + let mut headers = Headers::new(); + headers.set(HyperRange::Bytes(vec![ByteRangeSpec::AllFrom( + offset.unwrap_or(0), + )])); + let request = RequestInit { + url: self.resource_url.borrow().as_ref().unwrap().clone(), + headers, + destination, + credentials_mode: CredentialsMode::Include, + use_url_credentials: true, + origin: document.origin().immutable().clone(), + pipeline_id: Some(self.global().pipeline_id()), + referrer_url: Some(document.url()), + referrer_policy: document.get_referrer_policy(), + ..RequestInit::default() + }; + + let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self))); + let (action_sender, action_receiver) = ipc::channel().unwrap(); + let window = window_from_node(self); + let listener = NetworkListener { + context, + task_source: window.networking_task_source(), + canceller: Some(window.task_canceller(TaskSourceName::Networking)), + }; + ROUTER.add_route( + action_receiver.to_opaque(), + Box::new(move |message| { + listener.notify_fetch(message.to().unwrap()); + }), + ); + // This method may be called the first time we try to fetch the media + // resource or after a seek is requested. In the latter case, we need to + // cancel any previous on-going request. initialize() takes care of + // cancelling previous fetches if any exist. + let cancel_receiver = self.fetch_canceller.borrow_mut().initialize(); + let global = self.global(); + global + .core_resource_thread() + .send(CoreResourceMsg::Fetch( + request, + FetchChannels::ResponseMsg(action_sender, Some(cancel_receiver)), + )) + .unwrap(); + } + // https://html.spec.whatwg.org/multipage/#concept-media-load-resource fn resource_fetch_algorithm(&self, resource: Resource) { if let Err(e) = self.setup_media_player() { @@ -677,6 +747,14 @@ impl HTMLMediaElement { self.queue_dedicated_media_source_failure_steps(); return; } + + // XXX(ferjm) Since we only support Blob for now it is fine to always set + // the stream type to StreamType::Seekable. Once we support MediaStream, + // this should be changed to also consider StreamType::Stream. + if let Err(e) = self.player.set_stream_type(StreamType::Seekable) { + eprintln!("Could not set stream type to Seekable. {:?}", e); + } + // Steps 1-2. // Unapplicable, the `resource` variable already conveys which mode // is in use. @@ -724,47 +802,8 @@ impl HTMLMediaElement { } // Step 4.remote.2. - // FIXME(nox): Handle CORS setting from crossorigin attribute. - let document = document_from_node(self); - let destination = match self.media_type_id() { - HTMLMediaElementTypeId::HTMLAudioElement => Destination::Audio, - HTMLMediaElementTypeId::HTMLVideoElement => Destination::Video, - }; - let request = RequestInit { - url, - destination, - credentials_mode: CredentialsMode::Include, - use_url_credentials: true, - origin: document.origin().immutable().clone(), - pipeline_id: Some(self.global().pipeline_id()), - referrer_url: Some(document.url()), - referrer_policy: document.get_referrer_policy(), - ..RequestInit::default() - }; - - let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self))); - let (action_sender, action_receiver) = ipc::channel().unwrap(); - let window = window_from_node(self); - let listener = NetworkListener { - context: context, - task_source: window.networking_task_source(), - canceller: Some(window.task_canceller(TaskSourceName::Networking)), - }; - ROUTER.add_route( - action_receiver.to_opaque(), - Box::new(move |message| { - listener.notify_fetch(message.to().unwrap()); - }), - ); - let cancel_receiver = self.fetch_canceller.borrow_mut().initialize(); - let global = self.global(); - global - .core_resource_thread() - .send(CoreResourceMsg::Fetch( - request, - FetchChannels::ResponseMsg(action_sender, Some(cancel_receiver)), - )) - .unwrap(); + *self.resource_url.borrow_mut() = Some(url); + self.fetch_request(None); }, Resource::Object => { // FIXME(nox): Actually do something with the object. @@ -877,11 +916,16 @@ impl HTMLMediaElement { } // Step 6.7. - // FIXME(nox): If seeking is true, set it to false. + if !self.seeking.get() { + self.seeking.set(false); + } // Step 6.8. - // FIXME(nox): Set current and official playback position to 0 and - // maybe queue a task to fire a timeupdate event. + let queue_timeupdate_event = self.playback_position.get() != 0.; + self.playback_position.set(0.); + if queue_timeupdate_event { + task_source.queue_simple_event(self.upcast(), atom!("timeupdate"), &window); + } // Step 6.9. // FIXME(nox): Set timeline offset to NaN. @@ -972,7 +1016,7 @@ impl HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#dom-media-seek - fn seek(&self, time: f64, approximate_for_speed: bool) { + fn seek(&self, time: f64, _approximate_for_speed: bool) { // Step 1. self.show_poster.set(false); @@ -1002,10 +1046,18 @@ impl HTMLMediaElement { let time = f64::max(time, 0.); // Step 8. - // XXX(ferjm) seekable attribute. + // XXX(ferjm) seekable attribute: we need to get the information about + // what's been decoded and buffered so far from servo-media + // and turn the seekable attribute into a TimeRange. + // For now we use a boolean flag that is true iff the server + // supports byte-range requests. + if !self.seekable.get() { + self.seeking.set(false); + return; + } // Step 9. - let accurate = !approximate_for_speed; + // servo-media with gstreamer does not support inaccurate seeking for now. // Step 10. let window = window_from_node(self); @@ -1013,7 +1065,9 @@ impl HTMLMediaElement { task_source.queue_simple_event(self.upcast(), atom!("seeking"), &window); // Step 11. - // XXX self.player.seek(time, accurate); + if let Err(e) = self.player.seek(time) { + eprintln!("Seek error {:?}", e); + } // The rest of the steps are handled when the media engine signals a // ready state change or otherwise satisfies seek completion and signals @@ -1151,8 +1205,8 @@ impl HTMLMediaElement { PlayerEvent::FrameUpdated => { self.upcast::().dirty(NodeDamage::OtherNodeDamage); }, - PlayerEvent::SeekData(_) => { - // XXX byte-range request + PlayerEvent::SeekData(p) => { + self.fetch_request(Some(p)); }, PlayerEvent::SeekDone(_) => { // Continuation of @@ -1288,10 +1342,12 @@ impl HTMLMediaElementMethods for HTMLMediaElement { } } + // https://html.spec.whatwg.org/multipage/#dom-media-seeking fn Seeking(&self) -> bool { self.seeking.get() } + // https://html.spec.whatwg.org/multipage/#dom-media-fastseek fn FastSeek(&self, time: Finite) { self.seek(*time, /* approximat_for_speed */ true); } @@ -1424,6 +1480,14 @@ impl FetchResponseListener for HTMLMediaElementContext { eprintln!("Could not set player input size {:?}", e); } } + if let Some(accept_ranges) = headers.get::() { + self.elem + .root() + .seekable + .set(accept_ranges.contains(&RangeUnit::Bytes)); + } else { + self.elem.root().seekable.set(false); + } } } @@ -1497,6 +1561,8 @@ impl FetchResponseListener for HTMLMediaElementContext { elem.network_state.set(NetworkState::Idle); elem.upcast::().fire_event(atom!("suspend")); + + elem.delay_load_event(false); } // => "If the connection is interrupted after some media data has been received..." else if elem.ready_state.get() != ReadyState::HaveNothing { From 1f182d0bbd4f1ef074ad3ab4d165775a48af0c66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 24 Oct 2018 15:30:15 +0200 Subject: [PATCH 4/8] Remove seekable flag --- components/script/dom/htmlmediaelement.rs | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index baf5607ef2b..69a82754118 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -35,7 +35,7 @@ use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use fetch::FetchCanceller; use html5ever::{LocalName, Prefix}; -use hyper::header::{AcceptRanges, ByteRangeSpec, ContentLength, Headers, Range as HyperRange, RangeUnit}; +use hyper::header::{ByteRangeSpec, ContentLength, Headers, Range as HyperRange, RangeUnit}; use ipc_channel::ipc; use ipc_channel::router::ROUTER; use microtask::{Microtask, MicrotaskRunnable}; @@ -176,13 +176,6 @@ pub struct HTMLMediaElement { default_playback_start_position: Cell, /// https://html.spec.whatwg.org/multipage/#dom-media-seeking seeking: Cell, - /// Tells wether the current stream is seekable or not. - /// XXX(ferjm) This will eventually be changed by a TimeRange. - /// For now, we only consider a stream seekable if the server - /// supports byte-range requests. This should eventually change to - /// allow seeking to buffered content as well, even if the server - /// does not support byte-range requests. - seekable: Cell, /// URL of the media resource, if any. resource_url: DomRefCell>, } @@ -235,7 +228,6 @@ impl HTMLMediaElement { playback_position: Cell::new(0.), default_playback_start_position: Cell::new(0.), seeking: Cell::new(false), - seekable: Cell::new(false), resource_url: DomRefCell::new(None), } } @@ -1051,10 +1043,6 @@ impl HTMLMediaElement { // and turn the seekable attribute into a TimeRange. // For now we use a boolean flag that is true iff the server // supports byte-range requests. - if !self.seekable.get() { - self.seeking.set(false); - return; - } // Step 9. // servo-media with gstreamer does not support inaccurate seeking for now. @@ -1480,14 +1468,6 @@ impl FetchResponseListener for HTMLMediaElementContext { eprintln!("Could not set player input size {:?}", e); } } - if let Some(accept_ranges) = headers.get::() { - self.elem - .root() - .seekable - .set(accept_ranges.contains(&RangeUnit::Bytes)); - } else { - self.elem.root().seekable.set(false); - } } } From d94cbc83fc9bb4fb8940900c3e320df3c9d9ed0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 24 Oct 2018 15:31:34 +0200 Subject: [PATCH 5/8] Fix loadedmetadata event handler --- components/script/dom/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index 601426b91ea..d7281e5bc9c 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -451,7 +451,7 @@ macro_rules! global_event_handlers( event_handler!(keypress, GetOnkeypress, SetOnkeypress); event_handler!(keyup, GetOnkeyup, SetOnkeyup); event_handler!(loadeddata, GetOnloadeddata, SetOnloadeddata); - event_handler!(loadedmetata, GetOnloadedmetadata, SetOnloadedmetadata); + event_handler!(loadedmetadata, GetOnloadedmetadata, SetOnloadedmetadata); event_handler!(loadstart, GetOnloadstart, SetOnloadstart); event_handler!(mousedown, GetOnmousedown, SetOnmousedown); event_handler!(mouseenter, GetOnmouseenter, SetOnmouseenter); From aa3c911efa831e9d94f44c28ef1230e5a08d6818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 24 Oct 2018 15:45:40 +0200 Subject: [PATCH 6/8] HTMLMediaElement.seek: clean-up and update WPTs expectations --- components/script/dom/htmlmediaelement.rs | 11 +- .../currentTime.html.ini | 15 --- .../seeking/seek-to-currentTime.html.ini | 3 +- .../seeking/seek-to-max-value.htm.ini | 3 +- .../seeking/seek-to-negative-time.htm.ini | 3 +- .../event-handler-all-global-events.html.ini | 127 +++++++++++++++++- 6 files changed, 130 insertions(+), 32 deletions(-) delete mode 100644 tests/wpt/metadata/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html.ini diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 69a82754118..43fdbefa9bd 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -35,7 +35,7 @@ use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use fetch::FetchCanceller; use html5ever::{LocalName, Prefix}; -use hyper::header::{ByteRangeSpec, ContentLength, Headers, Range as HyperRange, RangeUnit}; +use hyper::header::{ByteRangeSpec, ContentLength, Headers, Range as HyperRange}; use ipc_channel::ipc; use ipc_channel::router::ROUTER; use microtask::{Microtask, MicrotaskRunnable}; @@ -1040,9 +1040,7 @@ impl HTMLMediaElement { // Step 8. // XXX(ferjm) seekable attribute: we need to get the information about // what's been decoded and buffered so far from servo-media - // and turn the seekable attribute into a TimeRange. - // For now we use a boolean flag that is true iff the server - // supports byte-range requests. + // and add the seekable attribute as a TimeRange. // Step 9. // servo-media with gstreamer does not support inaccurate seeking for now. @@ -1177,11 +1175,6 @@ impl HTMLMediaElement { }, _ => {}, }, - PlayerEvent::PositionChanged(_) | - PlayerEvent::SeekData(_) | - PlayerEvent::SeekDone(_) => { - // TODO: Support for HTMLMediaElement seeking and related API properties #21998 - }, PlayerEvent::EndOfStream => { // 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 diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html.ini deleted file mode 100644 index 39211dc575d..00000000000 --- a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html.ini +++ /dev/null @@ -1,15 +0,0 @@ -[currentTime.html] - type: testharness - expected: TIMEOUT - [currentTime initial value] - expected: FAIL - - [setting currentTime with a media controller present] - expected: FAIL - - [setting currentTime when readyState is HAVE_NOTHING] - expected: FAIL - - [setting currentTime when readyState is greater than HAVE_NOTHING] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html.ini index 57802dcd9c9..46f1c3a443e 100644 --- a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/seeking/seek-to-currentTime.html.ini @@ -1,6 +1,5 @@ [seek-to-currentTime.html] type: testharness - expected: TIMEOUT [seek to currentTime] - expected: TIMEOUT + expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/seeking/seek-to-max-value.htm.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/seeking/seek-to-max-value.htm.ini index ce89db5585d..07155918f41 100644 --- a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/seeking/seek-to-max-value.htm.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/seeking/seek-to-max-value.htm.ini @@ -1,6 +1,5 @@ [seek-to-max-value.htm] type: testharness - expected: TIMEOUT [seek to Number.MAX_VALUE] - expected: TIMEOUT + expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/seeking/seek-to-negative-time.htm.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/seeking/seek-to-negative-time.htm.ini index a53871348f9..3138b6cad17 100644 --- a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/seeking/seek-to-negative-time.htm.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/seeking/seek-to-negative-time.htm.ini @@ -1,6 +1,5 @@ [seek-to-negative-time.htm] type: testharness - expected: TIMEOUT [seek to negative time] - expected: TIMEOUT + expected: FAIL diff --git a/tests/wpt/metadata/html/webappapis/scripting/events/event-handler-all-global-events.html.ini b/tests/wpt/metadata/html/webappapis/scripting/events/event-handler-all-global-events.html.ini index be0a8e584fa..9f830c72535 100644 --- a/tests/wpt/metadata/html/webappapis/scripting/events/event-handler-all-global-events.html.ini +++ b/tests/wpt/metadata/html/webappapis/scripting/events/event-handler-all-global-events.html.ini @@ -5,253 +5,376 @@ [onabort: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onabort: the default value must be null] expected: FAIL + [onauxclick: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onauxclick: the default value must be null] expected: FAIL + [onauxclick: the content attribute must be compiled into a function as the corresponding property] expected: FAIL + [onblur: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onblur: the default value must be null] expected: FAIL + [oncancel: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [oncancel: the default value must be null] expected: FAIL + [oncanplay: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [oncanplay: the default value must be null] expected: FAIL + [oncanplaythrough: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [oncanplaythrough: the default value must be null] expected: FAIL + [onchange: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onchange: the default value must be null] expected: FAIL + [onclick: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onclick: the default value must be null] expected: FAIL + [onclose: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onclose: the default value must be null] expected: FAIL + [oncontextmenu: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [oncontextmenu: the default value must be null] expected: FAIL + [oncuechange: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [oncuechange: the default value must be null] expected: FAIL + [ondblclick: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [ondblclick: the default value must be null] expected: FAIL + [ondrag: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [ondrag: the default value must be null] expected: FAIL + [ondragend: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [ondragend: the default value must be null] expected: FAIL + [ondragenter: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [ondragenter: the default value must be null] expected: FAIL + [ondragexit: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [ondragexit: the default value must be null] expected: FAIL + [ondragleave: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [ondragleave: the default value must be null] expected: FAIL + [ondragover: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [ondragover: the default value must be null] expected: FAIL + [ondragstart: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [ondragstart: the default value must be null] expected: FAIL + [ondrop: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [ondrop: the default value must be null] expected: FAIL + [ondurationchange: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [ondurationchange: the default value must be null] expected: FAIL + [onemptied: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onemptied: the default value must be null] expected: FAIL + [onended: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onended: the default value must be null] expected: FAIL + [onfocus: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onfocus: the default value must be null] expected: FAIL + [oninput: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [oninput: the default value must be null] expected: FAIL + [oninvalid: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [oninvalid: the default value must be null] expected: FAIL + [onkeydown: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onkeydown: the default value must be null] expected: FAIL + [onkeypress: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onkeypress: the default value must be null] expected: FAIL + [onkeyup: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onkeyup: the default value must be null] expected: FAIL + [onload: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onload: the default value must be null] expected: FAIL + [onloadeddata: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onloadeddata: the default value must be null] expected: FAIL + [onloadedmetadata: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onloadedmetadata: the default value must be null] expected: FAIL - [onloadedmetadata: the content attribute must be compiled into a function as the corresponding property] - expected: FAIL + [onloadend: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onloadend: the default value must be null] expected: FAIL + [onloadend: the content attribute must be compiled into a function as the corresponding property] expected: FAIL + [onloadstart: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onloadstart: the default value must be null] expected: FAIL + [onmousedown: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onmousedown: the default value must be null] expected: FAIL + [onmouseenter: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onmouseenter: the default value must be null] expected: FAIL + [onmouseleave: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onmouseleave: the default value must be null] expected: FAIL + [onmousemove: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onmousemove: the default value must be null] expected: FAIL + [onmouseout: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onmouseout: the default value must be null] expected: FAIL + [onmouseover: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onmouseover: the default value must be null] expected: FAIL + [onmouseup: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onmouseup: the default value must be null] expected: FAIL + [onwheel: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onwheel: the default value must be null] expected: FAIL + [onpause: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onpause: the default value must be null] expected: FAIL + [onplay: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onplay: the default value must be null] expected: FAIL + [onplaying: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onplaying: the default value must be null] expected: FAIL + [onprogress: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onprogress: the default value must be null] expected: FAIL + [onratechange: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onratechange: the default value must be null] expected: FAIL + [onreset: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onreset: the default value must be null] expected: FAIL + [onresize: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onresize: the default value must be null] expected: FAIL + [onscroll: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onscroll: the default value must be null] expected: FAIL + [onsecuritypolicyviolation: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onsecuritypolicyviolation: the default value must be null] expected: FAIL + [onsecuritypolicyviolation: the content attribute must be compiled into a function as the corresponding property] expected: FAIL + [onseeked: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onseeked: the default value must be null] expected: FAIL + [onseeking: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onseeking: the default value must be null] expected: FAIL + [onselect: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onselect: the default value must be null] expected: FAIL + [onstalled: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onstalled: the default value must be null] expected: FAIL + [onsubmit: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onsubmit: the default value must be null] expected: FAIL + [onsuspend: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onsuspend: the default value must be null] expected: FAIL + [ontimeupdate: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [ontimeupdate: the default value must be null] expected: FAIL + [ontoggle: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [ontoggle: the default value must be null] expected: FAIL + [onvolumechange: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onvolumechange: the default value must be null] expected: FAIL + [onwaiting: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL + [onwaiting: the default value must be null] expected: FAIL + From 7bf1944007972f904e72ab43131556170c74578e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 25 Oct 2018 13:42:26 +0200 Subject: [PATCH 7/8] Rename seek_sync to seek_end --- components/script/dom/htmlmediaelement.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 43fdbefa9bd..9aeabaed8b2 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -1061,7 +1061,7 @@ impl HTMLMediaElement { } // https://html.spec.whatwg.org/multipage/#dom-media-seek - fn seek_sync(&self) { + fn seek_end(&self) { // Step 14. self.seeking.set(false); @@ -1417,7 +1417,7 @@ impl MicrotaskRunnable for MediaElementMicrotask { generation_id, } => { if generation_id == elem.generation_id.get() { - elem.seek_sync(); + elem.seek_end(); } }, } From d7629b7d384128f79969689e99cfe7f922d495ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 26 Oct 2018 16:34:10 +0200 Subject: [PATCH 8/8] Update interfaces test expectations --- .../html/dom/interfaces.https.html.ini | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/tests/wpt/metadata/html/dom/interfaces.https.html.ini b/tests/wpt/metadata/html/dom/interfaces.https.html.ini index 2b1821443e2..4a2b8246a86 100644 --- a/tests/wpt/metadata/html/dom/interfaces.https.html.ini +++ b/tests/wpt/metadata/html/dom/interfaces.https.html.ini @@ -6783,18 +6783,6 @@ [HTMLMediaElement interface: document.createElement("video") must inherit property "buffered" with the proper type] expected: FAIL - [HTMLMediaElement interface: document.createElement("video") must inherit property "seeking" with the proper type] - expected: FAIL - - [HTMLMediaElement interface: document.createElement("video") must inherit property "currentTime" with the proper type] - expected: FAIL - - [HTMLMediaElement interface: document.createElement("video") must inherit property "fastSeek(double)" with the proper type] - expected: FAIL - - [HTMLMediaElement interface: calling fastSeek(double) on document.createElement("video") with too few arguments must throw TypeError] - expected: FAIL - [HTMLMediaElement interface: document.createElement("video") must inherit property "getStartDate()" with the proper type] expected: FAIL @@ -6852,18 +6840,6 @@ [HTMLMediaElement interface: document.createElement("audio") must inherit property "buffered" with the proper type] expected: FAIL - [HTMLMediaElement interface: document.createElement("audio") must inherit property "seeking" with the proper type] - expected: FAIL - - [HTMLMediaElement interface: document.createElement("audio") must inherit property "currentTime" with the proper type] - expected: FAIL - - [HTMLMediaElement interface: document.createElement("audio") must inherit property "fastSeek(double)" with the proper type] - expected: FAIL - - [HTMLMediaElement interface: calling fastSeek(double) on document.createElement("audio") with too few arguments must throw TypeError] - expected: FAIL - [HTMLMediaElement interface: document.createElement("audio") must inherit property "getStartDate()" with the proper type] expected: FAIL @@ -7140,15 +7116,6 @@ [HTMLMediaElement interface: attribute buffered] expected: FAIL - [HTMLMediaElement interface: attribute seeking] - expected: FAIL - - [HTMLMediaElement interface: attribute currentTime] - expected: FAIL - - [HTMLMediaElement interface: operation fastSeek(double)] - expected: FAIL - [HTMLMediaElement interface: operation getStartDate()] expected: FAIL