From c8bc9c8740097eba74281215ab20b3b3ccb07839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Sat, 18 Aug 2018 19:25:50 +0200 Subject: [PATCH 01/38] htmlmediaelement: typo --- components/script/dom/htmlmediaelement.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index ad2a487a16f..13f6959e204 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -416,7 +416,7 @@ impl HTMLMediaElement { base_url: doc.base_url(), }; - // FIXME(nox): This will later call the resource_selection_algorith_sync + // FIXME(nox): This will later call the resource_selection_algorithm_sync // method from below, if microtasks were trait objects, we would be able // to put the code directly in this method, without the boilerplate // indirections. From 0ff9ecc18ac0fadf45f2e64192fe2e1d86760806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Wed, 22 Aug 2018 12:59:04 +0200 Subject: [PATCH 02/38] add a fixme message of not implemented mode --- components/script/dom/htmlmediaelement.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 13f6959e204..6a89500e3fb 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -515,6 +515,7 @@ impl HTMLMediaElement { }, Mode::Children(_source) => { // Step 9.children. + // FIXME(victor): seems not implemeted yet self.queue_dedicated_media_source_failure_steps() }, } From ce76b5780a45a9e00ae3a235185d2ea15c6b688b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Thu, 2 Aug 2018 14:09:45 +0200 Subject: [PATCH 03/38] dom: htmlmediaelement: add initial player bits Also removes the usage of audio-video-metadata crate (?) --- Cargo.lock | 55 --------- components/script/Cargo.toml | 1 - components/script/dom/htmlmediaelement.rs | 129 +++++++++++++++++----- components/script/lib.rs | 1 - 4 files changed, 101 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 35444b693a6..8c7da7e5584 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -97,16 +97,6 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "audio-video-metadata" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "mp3-metadata 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "mp4parse 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ogg_metadata 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "azure" version = "0.34.0" @@ -193,11 +183,6 @@ name = "bitflags" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "bitreader" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "block" version = "0.1.6" @@ -2241,22 +2226,6 @@ dependencies = [ "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "mp3-metadata" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "mp4parse" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "msdos_time" version = "0.1.6" @@ -2497,23 +2466,6 @@ dependencies = [ "x11 2.17.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ogg" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ogg_metadata" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ogg 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "openssl" version = "0.9.24" @@ -2981,7 +2933,6 @@ name = "script" version = "0.0.1" dependencies = [ "app_units 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "audio-video-metadata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4344,7 +4295,6 @@ dependencies = [ "checksum ascii 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50" "checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21" "checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860" -"checksum audio-video-metadata 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3c23600291b35b9cd381f5cfca636f5d7d75e7d7192eddf867de84a6732cad5c" "checksum azure 0.34.0 (git+https://github.com/servo/rust-azure)" = "" "checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" "checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" @@ -4354,7 +4304,6 @@ dependencies = [ "checksum bindgen 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eac4ed5f2de9efc3c87cb722468fa49d0763e98f999d539bfc5e452c13d85c91" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" -"checksum bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80b13e2ab064ff3aa0bdbf1eff533f9822dc37899821f5f98c67f263eab51707" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" "checksum blurdroid 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "19b23557dd27704797128f9db2816416bef20dad62d4a9768714eeb65f07d296" "checksum blurmac 0.1.0 (git+https://github.com/servo/devices)" = "" @@ -4519,8 +4468,6 @@ dependencies = [ "checksum mozangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "45a8a18a41cfab0fde25cc2f43ea89064d211a0fbb33225b8ff93ab20406e0e7" "checksum mozjs 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b9f85c1120b07d7a2acc9d1d62df1fe16f64162399448fb5307bf2bc3bd066c9" "checksum mozjs_sys 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff07b0f0a2371dc08d75d55371ca311be67e1fdfa6c146fc8ad154c340f70c9" -"checksum mp3-metadata 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ab5f1d2693586420208d1200ce5a51cd44726f055b635176188137aff42c7de" -"checksum mp4parse 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7316728464443fe5793a805dde3257864e9690cf46374daff3ce93de1df2f254" "checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729" "checksum muldiv 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "451a9a05d2a32c566c897835e0ea95cf79ed2fdfe957924045a1721a36c9980f" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" @@ -4539,8 +4486,6 @@ dependencies = [ "checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" "checksum objc_id 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e4730aa1c64d722db45f7ccc4113a3e2c465d018de6db4d3e7dfe031e8c8a297" "checksum offscreen_gl_context 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "95f2e39e3b8c95495cfec835b6fefee3f1e7d63c6f81d99796b4f9926c02db3c" -"checksum ogg 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7137bf02687385302f4c0aecd77cfce052b69f5b4ee937be778e125c62f67e30" -"checksum ogg_metadata 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc665717454399cba557c55ad226148996e9266ee291f8a37a98bb2cded0a490" "checksum openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "a3605c298474a3aa69de92d21139fb5e2a81688d308262359d85cdd0d12a7985" "checksum openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdc5c4a02e69ce65046f1763a0181107038e02176233acb0b3351d7cc588f9" "checksum ordered-float 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a3c8db0fca1fdb34404f0b1286db252f23930b9f7a481e376c16c0d5c309d4" diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 913edf25f2e..52108a89c59 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -30,7 +30,6 @@ tinyfiledialogs = "3.0" [dependencies] app_units = "0.7" -audio-video-metadata = "0.1.4" backtrace = {version = "0.3", optional = true} base64 = "0.6" bitflags = "1.0" diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 6a89500e3fb..f726648f5d2 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -2,7 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use audio_video_metadata; use document_loader::{LoadBlocker, LoadType}; use dom::attr::Attr; use dom::bindings::cell::DomRefCell; @@ -40,6 +39,8 @@ use net_traits::{FetchResponseListener, FetchMetadata, Metadata, NetworkError}; use net_traits::request::{CredentialsMode, Destination, RequestInit}; use network_listener::{NetworkListener, PreInvoke}; use script_thread::ScriptThread; +use servo_media::player::{PlaybackState, Player, PlayerEvent}; +use servo_media::ServoMedia; use servo_url::ServoUrl; use std::cell::Cell; use std::collections::VecDeque; @@ -49,6 +50,8 @@ use std::sync::{Arc, Mutex}; use task_source::{TaskSource, TaskSourceName}; use time::{self, Timespec, Duration}; +unsafe_no_jsmanaged_fields!(Arc>>); + #[dom_struct] // FIXME(nox): A lot of tasks queued for this element should probably be in the // media element event task source. @@ -82,6 +85,10 @@ pub struct HTMLMediaElement { /// Play promises which are soon to be fulfilled by a queued task. #[ignore_malloc_size_of = "promises are hard"] in_flight_play_promises_queue: DomRefCell]>, ErrorResult)>>, + /// Whether the media metadata has been completely received. + have_metadata: Cell, + #[ignore_malloc_size_of = "servo_media"] + player: Arc>>, } /// @@ -122,6 +129,10 @@ impl HTMLMediaElement { delaying_the_load_event_flag: Default::default(), pending_play_promises: Default::default(), in_flight_play_promises_queue: Default::default(), + have_metadata: Cell::new(false), + player: Arc::new(Mutex::new( + ServoMedia::get().unwrap().create_player().unwrap(), + )), } } @@ -217,7 +228,9 @@ impl HTMLMediaElement { return; } - this.fulfill_in_flight_play_promises(|| ()); + this.fulfill_in_flight_play_promises(|| { + this.player.lock().unwrap().play(); + }); }), window.upcast(), ).unwrap(); @@ -263,6 +276,9 @@ impl HTMLMediaElement { // Step 2.3.2. this.upcast::().fire_event(atom!("pause")); + //FIXME(victor) + //this.player.lock().unwrap().pause(); + // Step 2.3.3. // Done after running this closure in // `fulfill_in_flight_play_promises`. @@ -298,6 +314,7 @@ impl HTMLMediaElement { this.fulfill_in_flight_play_promises(|| { // Step 2.1. this.upcast::().fire_event(atom!("playing")); + this.player.lock().unwrap().play(); // Step 2.2. // Done after running this closure in @@ -587,6 +604,7 @@ impl HTMLMediaElement { ..RequestInit::default() }; + self.setup_media_player(); let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self))); let (action_sender, action_receiver) = ipc::channel().unwrap(); let window = window_from_node(self); @@ -648,6 +666,8 @@ impl HTMLMediaElement { // Step 5. this.upcast::().fire_event(atom!("error")); + this.player.lock().unwrap().stop(); + // Step 6. // Done after running this closure in // `fulfill_in_flight_play_promises`. @@ -806,6 +826,72 @@ impl HTMLMediaElement { } self.media_element_load_algorithm(); } + + // servo media player + fn setup_media_player(&self) { + let (action_sender, action_receiver) = ipc::channel().unwrap(); + + self.player + .lock() + .unwrap() + .register_event_handler(action_sender); + self.player.lock().unwrap().setup().unwrap(); + + let trusted_node = Trusted::new(self); + let window = window_from_node(self); + let task_source = window.dom_manipulation_task_source(); + let task_canceller = window.task_canceller(TaskSourceName::DOMManipulation); + ROUTER.add_route( + action_receiver.to_opaque(), + Box::new(move |message| { + let event: PlayerEvent = message.to().unwrap(); + let this = trusted_node.clone(); + task_source + .queue_with_canceller( + task!(handle_player_event: move || { + this.root().handle_player_event(&event); + }), + &task_canceller, + ).unwrap(); + }), + ); + } + + fn handle_player_event(&self, event: &PlayerEvent) { + match *event { + PlayerEvent::MetadataUpdated(ref metadata) => { + if !self.have_metadata.get() { + // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list + // => "Once enough of the media data has been fetched to determine the duration..." + if let Some(_dur) = metadata.duration { + // Setp 6. + self.change_ready_state(ReadyState::HaveMetadata); + self.have_metadata.set(true); + } + } else { + // => set the element's delaying-the-load-event flag to false + self.change_ready_state(ReadyState::HaveCurrentData); + } + } + PlayerEvent::StateChanged(ref state) => match *state { + PlaybackState::Paused => { + if self.ready_state.get() == ReadyState::HaveMetadata { + self.change_ready_state(ReadyState::HaveEnoughData); + } + } + _ => {} + }, + PlayerEvent::EndOfStream => {} + PlayerEvent::FrameUpdated => {} + PlayerEvent::Error => { + self.error.set(Some(&*MediaError::new( + &*window_from_node(self), + MEDIA_ERR_DECODE, + ))); + self.upcast::().fire_event(atom!("error")); + } + } + } } impl HTMLMediaElementMethods for HTMLMediaElement { @@ -969,16 +1055,12 @@ enum Resource { struct HTMLMediaElementContext { /// The element that initiated the request. elem: Trusted, - /// The response body received to date. - data: Vec, /// The response metadata received to date. metadata: Option, /// The generation of the media element when this fetch started. generation_id: u32, /// Time of last progress notification. next_progress_event: Timespec, - /// Whether the media metadata has been completely received. - have_metadata: bool, /// True if this response is invalid and should be ignored. ignore_response: bool, } @@ -1012,22 +1094,17 @@ impl FetchResponseListener for HTMLMediaElementContext { } } - fn process_response_chunk(&mut self, mut payload: Vec) { + fn process_response_chunk(&mut self, payload: Vec) { if self.ignore_response { // An error was received previously, skip processing the payload. return; } - self.data.append(&mut payload); - let elem = self.elem.root(); - // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list - // => "Once enough of the media data has been fetched to determine the duration..." - if !self.have_metadata { - self.check_metadata(&elem); - } else { - elem.change_ready_state(ReadyState::HaveCurrentData); + // push input data into the player + if let Err(_) = elem.player.lock().unwrap().push_data(payload) { + eprintln!("Couldn't push input data to player"); } // https://html.spec.whatwg.org/multipage/#concept-media-load-resource step 4, @@ -1050,14 +1127,20 @@ impl FetchResponseListener for HTMLMediaElementContext { return; } let elem = self.elem.root(); + let player = elem.player.lock().unwrap(); + + // signal the eos to player + if let Err(_) = player.end_of_stream() { + eprintln!("Couldn't signal EOS to player"); + } // => "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.have_metadata { + if !elem.have_metadata.get() { + // FIXME(victor): adjust player's max-size (or buffering) elem.queue_dedicated_media_source_failure_steps(); - } // => "Once the entire media resource has been fetched..." - else if status.is_ok() { + } else if status.is_ok() { elem.change_ready_state(ReadyState::HaveEnoughData); elem.upcast::().fire_event(atom!("progress")); @@ -1100,20 +1183,10 @@ impl HTMLMediaElementContext { fn new(elem: &HTMLMediaElement) -> HTMLMediaElementContext { HTMLMediaElementContext { elem: Trusted::new(elem), - data: vec![], metadata: None, generation_id: elem.generation_id.get(), next_progress_event: time::get_time() + Duration::milliseconds(350), - have_metadata: false, ignore_response: false, } } - - fn check_metadata(&mut self, elem: &HTMLMediaElement) { - if audio_video_metadata::get_format_from_slice(&self.data).is_ok() { - // Step 6. - elem.change_ready_state(ReadyState::HaveMetadata); - self.have_metadata = true; - } - } } diff --git a/components/script/lib.rs b/components/script/lib.rs index 097f69d7808..eda29279bae 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -18,7 +18,6 @@ )] extern crate app_units; -extern crate audio_video_metadata; #[cfg(any(feature = "webgl_backtrace", feature = "js_backtrace"))] extern crate backtrace; extern crate base64; From 77c7eda0bfe659fde191d0bb48cf6b124a5f4fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Tue, 21 Aug 2018 17:59:09 +0200 Subject: [PATCH 04/38] HACK: don't call media_source_failure_steps when eos Because gstreamer's appsrc queue might be big enough to swallow the whole video holding the metadata extraction until EOS. --- 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 f726648f5d2..292d1b8a6a5 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -1138,8 +1138,8 @@ impl FetchResponseListener for HTMLMediaElementContext { // format, or can otherwise not be rendered at all" if !elem.have_metadata.get() { // FIXME(victor): adjust player's max-size (or buffering) - elem.queue_dedicated_media_source_failure_steps(); - // => "Once the entire media resource has been fetched..." + //elem.queue_dedicated_media_source_failure_steps(); + // => "Once the entire media resource has been fetched..." } else if status.is_ok() { elem.change_ready_state(ReadyState::HaveEnoughData); From 781b3b712bd328b2c94afc2196382ee6807ebfde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Wed, 22 Aug 2018 18:13:13 +0200 Subject: [PATCH 05/38] Provide webrender_api::RenderApiSender to ScriptThread and DOM Window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow the HTMLMediaElement later to get a handle to the RenderApi for rendering video frames. At a later time, all media handling should be moved to its own thread/process that is communicated with via IPC. At that point this can be removed again. Original-patch-by: Sebastian Dröge --- components/constellation/pipeline.rs | 1 + components/script/dom/window.rs | 21 ++++++++++++++++++++- components/script/script_thread.rs | 7 ++++++- components/script_traits/lib.rs | 6 +++++- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index d110bbfcdce..d37d4d80f07 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -517,6 +517,7 @@ impl UnprivilegedPipelineContent { webgl_chan: self.webgl_chan, webvr_chan: self.webvr_chan, webrender_document: self.webrender_document, + webrender_api_sender: self.webrender_api_sender.clone(), }, self.load_data.clone(), ); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index ff905ab55b5..b6c7a460103 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -132,7 +132,9 @@ use time; use timers::{IsInterval, TimerCallback}; use url::Position; use webdriver_handlers::jsval_to_webdriver; -use webrender_api::{ExternalScrollId, DeviceIntPoint, DeviceUintSize, DocumentId}; +use webrender_api::{ + DeviceIntPoint, DeviceUintSize, DocumentId, ExternalScrollId, RenderApiSender, +}; use webvr_traits::WebVRMsg; /// Current state of the window object @@ -308,6 +310,17 @@ pub struct Window { /// Flag to identify whether mutation observers are present(true)/absent(false) exists_mut_observer: Cell, + /// Webrender API Sender + #[ignore_malloc_size_of = "defined in webrender_api"] + webrender_api_sender: RenderApiSender, +} + +// FIXME(victor): this doesn't belong here +#[allow(unsafe_code)] +unsafe impl ::dom::bindings::trace::JSTraceable for RenderApiSender { + unsafe fn trace(&self, _trc: *mut ::js::jsapi::JSTracer) { + // Do nothing + } } impl Window { @@ -483,6 +496,10 @@ impl Window { } self.add_pending_reflow(); } + + pub fn get_webrender_api_sender(&self) -> RenderApiSender { + self.webrender_api_sender.clone() + } } // https://html.spec.whatwg.org/multipage/#atob @@ -2083,6 +2100,7 @@ impl Window { webvr_chan: Option>, microtask_queue: Rc, webrender_document: DocumentId, + webrender_api_sender: RenderApiSender, ) -> DomRoot { let layout_rpc: Box = { let (rpc_send, rpc_recv) = channel(); @@ -2161,6 +2179,7 @@ impl Window { paint_worklet: Default::default(), webrender_document, exists_mut_observer: Cell::new(false), + webrender_api_sender, }); unsafe { WindowBinding::Wrap(runtime.cx(), win) } diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 748b6fc63e4..687dd32e1df 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -130,7 +130,7 @@ use time::{get_time, precise_time_ns, Tm}; use url::Position; use url::percent_encoding::percent_decode; use webdriver_handlers; -use webrender_api::DocumentId; +use webrender_api::{DocumentId, RenderApiSender}; use webvr_traits::{WebVREvent, WebVRMsg}; pub type ImageCacheMsg = (PipelineId, PendingImageResponse); @@ -591,6 +591,9 @@ pub struct ScriptThread { /// The Webrender Document ID associated with this thread. webrender_document: DocumentId, + + /// FIXME(victor): + webrender_api_sender: RenderApiSender, } /// In the event of thread panic, all data on the stack runs its destructor. However, there @@ -1063,6 +1066,7 @@ impl ScriptThread { custom_element_reaction_stack: CustomElementReactionStack::new(), webrender_document: state.webrender_document, + webrender_api_sender: state.webrender_api_sender, } } @@ -2584,6 +2588,7 @@ impl ScriptThread { self.webvr_chan.clone(), self.microtask_queue.clone(), self.webrender_document, + self.webrender_api_sender.clone(), ); // Initialize the browsing context for the window. diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 6c087690b5f..60b62f6b270 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -72,7 +72,9 @@ use style_traits::CSSPixel; use style_traits::SpeculativePainter; use style_traits::cursor::CursorKind; use webdriver_msg::{LoadStatus, WebDriverScriptCommand}; -use webrender_api::{ExternalScrollId, DevicePixel, DeviceUintSize, DocumentId, ImageKey}; +use webrender_api::{ + DevicePixel, DeviceUintSize, DocumentId, ExternalScrollId, ImageKey, RenderApiSender, +}; use webvr_traits::{WebVREvent, WebVRMsg}; pub use script_msg::{LayoutMsg, ScriptMsg, EventResult, LogEntry}; @@ -588,6 +590,8 @@ pub struct InitialScriptState { pub webvr_chan: Option>, /// The Webrender document ID associated with this thread. pub webrender_document: DocumentId, + /// FIXME(victor): The Webrender API sender in this constellation's pipeline + pub webrender_api_sender: RenderApiSender, } /// This trait allows creating a `ScriptThread` without depending on the `script` From 6e3c2fe41a841ae178ea96e2f2b3b74212191737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Wed, 22 Aug 2018 16:44:02 +0200 Subject: [PATCH 06/38] dom: add mediaframewebrenderer --- components/script/dom/htmlmediaelement.rs | 15 +++- components/script/dom/mediaframerenderer.rs | 86 +++++++++++++++++++++ components/script/dom/mod.rs | 1 + 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 components/script/dom/mediaframerenderer.rs diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 292d1b8a6a5..f40eb2861b8 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -26,7 +26,8 @@ use dom::eventtarget::EventTarget; use dom::htmlelement::HTMLElement; use dom::htmlsourceelement::HTMLSourceElement; use dom::mediaerror::MediaError; -use dom::node::{window_from_node, document_from_node, Node, UnbindContext}; +use dom::mediaframerenderer::MediaFrameRenderer; +use dom::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindContext}; use dom::promise::Promise; use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; @@ -51,6 +52,7 @@ use task_source::{TaskSource, TaskSourceName}; use time::{self, Timespec, Duration}; unsafe_no_jsmanaged_fields!(Arc>>); +unsafe_no_jsmanaged_fields!(MediaFrameRenderer); #[dom_struct] // FIXME(nox): A lot of tasks queued for this element should probably be in the @@ -89,6 +91,8 @@ pub struct HTMLMediaElement { have_metadata: Cell, #[ignore_malloc_size_of = "servo_media"] player: Arc>>, + #[ignore_malloc_size_of = "oops"] + frame_renderer: MediaFrameRenderer, } /// @@ -133,6 +137,7 @@ impl HTMLMediaElement { player: Arc::new(Mutex::new( ServoMedia::get().unwrap().create_player().unwrap(), )), + frame_renderer: MediaFrameRenderer::new(document.window().get_webrender_api_sender()), } } @@ -835,6 +840,10 @@ impl HTMLMediaElement { .lock() .unwrap() .register_event_handler(action_sender); + self.player + .lock() + .unwrap() + .register_frame_renderer(Arc::new(self.frame_renderer.clone())); self.player.lock().unwrap().setup().unwrap(); let trusted_node = Trusted::new(self); @@ -882,7 +891,9 @@ impl HTMLMediaElement { _ => {} }, PlayerEvent::EndOfStream => {} - PlayerEvent::FrameUpdated => {} + PlayerEvent::FrameUpdated => { + self.upcast::().dirty(NodeDamage::OtherNodeDamage); + } PlayerEvent::Error => { self.error.set(Some(&*MediaError::new( &*window_from_node(self), diff --git a/components/script/dom/mediaframerenderer.rs b/components/script/dom/mediaframerenderer.rs new file mode 100644 index 00000000000..698051885a7 --- /dev/null +++ b/components/script/dom/mediaframerenderer.rs @@ -0,0 +1,86 @@ +use servo_media::player::frame::{Frame, FrameRenderer}; +use std::mem; +use std::sync::{Arc, Mutex}; +use webrender_api::{ + ImageData, ImageDescriptor, ImageFormat, ImageKey, RenderApi, RenderApiSender, Transaction, +}; + +#[derive(Clone)] +pub struct MediaFrameRenderer { + inner: Arc>, +} + +impl MediaFrameRenderer { + pub fn new(render_api_sender: RenderApiSender) -> MediaFrameRenderer { + MediaFrameRenderer { + inner: Arc::new(Mutex::new(MediaFrameRendererInner { + api: render_api_sender.create_api(), + current_frame: None, + old_frame: None, + very_old_frame: None, + })), + } + } +} + +impl FrameRenderer for MediaFrameRenderer { + fn render(&self, frame: Frame) { + self.inner.lock().unwrap().render(frame); + } +} + +struct MediaFrameRendererInner { + api: RenderApi, + current_frame: Option<(ImageKey, i32, i32)>, + old_frame: Option, + very_old_frame: Option, +} + +impl MediaFrameRendererInner { + fn render(&mut self, frame: Frame) { + let descriptor = ImageDescriptor::new( + frame.get_width() as u32, + frame.get_height() as u32, + ImageFormat::BGRA8, + false, + false, + ); + + let mut txn = Transaction::new(); + + //let image_data = ImageData::new_shared(frame.get_data().clone()); + let image_data = ImageData::Raw(frame.get_data().clone()); + + if let Some(old_image_key) = mem::replace(&mut self.very_old_frame, self.old_frame.take()) { + txn.delete_image(old_image_key); + } + + match self.current_frame { + Some((ref image_key, ref mut width, ref mut height)) + if *width == frame.get_width() && *height == frame.get_height() => + { + txn.update_image(*image_key, descriptor, image_data, None); + + if let Some(old_image_key) = self.old_frame.take() { + txn.delete_image(old_image_key); + } + } + Some((ref mut image_key, ref mut width, ref mut height)) => { + self.old_frame = Some(*image_key); + + let new_image_key = self.api.generate_image_key(); + txn.add_image(new_image_key, descriptor, image_data, None); + *image_key = new_image_key; + *width = frame.get_width(); + *height = frame.get_height(); + } + None => { + let image_key = self.api.generate_image_key(); + txn.add_image(image_key, descriptor, image_data, None); + self.current_frame = Some((image_key, frame.get_width(), frame.get_height())); + } + } + + self.api.update_resources(txn.resource_updates); + } +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 07425cccae1..10ed49f99a2 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -390,6 +390,7 @@ pub mod inputevent; pub mod keyboardevent; pub mod location; pub mod mediaerror; +pub mod mediaframerenderer; pub mod medialist; pub mod mediaquerylist; pub mod mediaquerylistevent; From 623229dd8a26c7cc31aac0070d9285bcdf9a59a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Mon, 27 Aug 2018 15:50:11 +0200 Subject: [PATCH 07/38] layout: add HTMLMediaFrameSource trait and HTMLMediaData struct --- components/script_layout_interface/lib.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index da1ab322fa9..0db0bbe3ef5 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -115,6 +115,7 @@ pub enum LayoutElementType { HTMLIFrameElement, HTMLImageElement, HTMLInputElement, + HTMLMediaElement, HTMLObjectElement, HTMLParagraphElement, HTMLTableCellElement, @@ -170,3 +171,13 @@ pub struct PendingImage { pub node: UntrustedNodeAddress, pub id: PendingImageId, } + +/// FIXME(victor): probably this doesn't belong here +pub trait HTMLMediaFrameSource: Send + Sync + 'static { + fn get_current_frame(&self) -> Option<(webrender_api::ImageKey, i32, i32)>; + fn clone_boxed(&self) -> Box; +} + +pub struct HTMLMediaData { + pub frame_source: Box, +} From 524750f41f22ddd933d2e72013dd97b284b24c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Mon, 27 Aug 2018 18:10:13 +0200 Subject: [PATCH 08/38] dom: framerenderer: implement HTMLMediaFrameSource trait for MediaFrameRenderer --- components/script/dom/mediaframerenderer.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/components/script/dom/mediaframerenderer.rs b/components/script/dom/mediaframerenderer.rs index 698051885a7..28a52c4bf7f 100644 --- a/components/script/dom/mediaframerenderer.rs +++ b/components/script/dom/mediaframerenderer.rs @@ -1,4 +1,5 @@ use servo_media::player::frame::{Frame, FrameRenderer}; +use script_layout_interface::HTMLMediaFrameSource; use std::mem; use std::sync::{Arc, Mutex}; use webrender_api::{ @@ -29,6 +30,17 @@ impl FrameRenderer for MediaFrameRenderer { } } +impl HTMLMediaFrameSource for MediaFrameRenderer { + fn get_current_frame(&self) -> Option<(ImageKey, i32, i32)> { + let inner = self.inner.lock().unwrap(); + inner.current_frame.clone() + } + + fn clone_boxed(&self) -> Box { + Box::new(self.clone()) + } +} + struct MediaFrameRendererInner { api: RenderApi, current_frame: Option<(ImageKey, i32, i32)>, From 74a9edfed329fe6927a977b2ebd1a40e741a92de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Mon, 27 Aug 2018 18:09:17 +0200 Subject: [PATCH 09/38] dom: media: implement LayoutHTMLMediaElementHelpers trait for LayoutDom --- components/script/dom/htmlmediaelement.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index f40eb2861b8..4aaad2986fc 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -17,7 +17,7 @@ use dom::bindings::error::{Error, ErrorResult}; use dom::bindings::inheritance::Castable; use dom::bindings::refcounted::Trusted; use dom::bindings::reflector::DomObject; -use dom::bindings::root::{DomRoot, MutNullableDom}; +use dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom}; use dom::bindings::str::DOMString; use dom::blob::Blob; use dom::document::Document; @@ -39,6 +39,7 @@ use mime::{Mime, SubLevel, TopLevel}; use net_traits::{FetchResponseListener, FetchMetadata, Metadata, NetworkError}; use net_traits::request::{CredentialsMode, Destination, RequestInit}; use network_listener::{NetworkListener, PreInvoke}; +use script_layout_interface::HTMLMediaData; use script_thread::ScriptThread; use servo_media::player::{PlaybackState, Player, PlayerEvent}; use servo_media::ServoMedia; @@ -1025,6 +1026,23 @@ impl VirtualMethods for HTMLMediaElement { } } +pub trait LayoutHTMLMediaElementHelpers { + fn data(&self) -> HTMLMediaData; +} + +impl LayoutHTMLMediaElementHelpers for LayoutDom { + #[allow(unsafe_code)] + fn data(&self) -> HTMLMediaData { + unsafe { + let media = &*self.unsafe_get(); + + HTMLMediaData { + frame_source: Box::new(media.frame_renderer.clone()), + } + } + } +} + #[derive(JSTraceable, MallocSizeOf)] pub enum MediaElementMicrotask { ResourceSelectionTask { From da5d1d462ffa47a13ea880e345edb8db7a8a353c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Mon, 27 Aug 2018 16:47:08 +0200 Subject: [PATCH 10/38] dom: add media_data() method to LayoutDom implementation --- components/script/dom/node.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 8fa494767f6..0c48d3d2df3 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -43,6 +43,7 @@ use dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementLayoutMethods}; use dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers}; use dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers}; use dom::htmllinkelement::HTMLLinkElement; +use dom::htmlmediaelement::{HTMLMediaElement, LayoutHTMLMediaElementHelpers}; use dom::htmlmetaelement::HTMLMetaElement; use dom::htmlstyleelement::HTMLStyleElement; use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers}; @@ -62,9 +63,11 @@ use libc::{self, c_void, uintptr_t}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use msg::constellation_msg::{BrowsingContextId, PipelineId}; use ref_slice::ref_slice; -use script_layout_interface::{HTMLCanvasData, OpaqueStyleAndLayoutData, SVGSVGData}; -use script_layout_interface::{LayoutElementType, LayoutNodeType, TrustedNodeAddress}; use script_layout_interface::message::Msg; +use script_layout_interface::{ + HTMLCanvasData, HTMLMediaData, LayoutElementType, LayoutNodeType, OpaqueStyleAndLayoutData, + SVGSVGData, TrustedNodeAddress, +}; use script_thread::ScriptThread; use script_traits::DocumentActivity; use script_traits::UntrustedNodeAddress; @@ -1086,6 +1089,7 @@ pub trait LayoutNodeHelpers { fn image_url(&self) -> Option; fn image_density(&self) -> Option; fn canvas_data(&self) -> Option; + fn media_data(&self) -> Option; fn svg_data(&self) -> Option; fn iframe_browsing_context_id(&self) -> Option; fn iframe_pipeline_id(&self) -> Option; @@ -1245,6 +1249,11 @@ impl LayoutNodeHelpers for LayoutDom { .map(|canvas| canvas.data()) } + fn media_data(&self) -> Option { + self.downcast::() + .map(|media| media.data()) + } + fn svg_data(&self) -> Option { self.downcast::().map(|svg| svg.data()) } @@ -2911,6 +2920,9 @@ impl Into for ElementTypeId { ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement) => { LayoutElementType::HTMLImageElement }, + ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMediaElement(_)) => { + LayoutElementType::HTMLMediaElement + }, ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement) => { LayoutElementType::HTMLInputElement }, From 1985f0d75e83c7a90de539d9e244383e15e2897b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Mon, 27 Aug 2018 14:28:42 +0200 Subject: [PATCH 11/38] layout: add media_data() method to ThreadSafeLayoutNode trait --- components/script_layout_interface/wrapper_traits.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs index 32cb4853fa4..9df6a7b44f4 100644 --- a/components/script_layout_interface/wrapper_traits.rs +++ b/components/script_layout_interface/wrapper_traits.rs @@ -5,6 +5,7 @@ #![allow(unsafe_code)] use HTMLCanvasData; +use HTMLMediaData; use LayoutNodeType; use OpaqueStyleAndLayoutData; use SVGSVGData; @@ -279,6 +280,8 @@ pub trait ThreadSafeLayoutNode: fn svg_data(&self) -> Option; + fn media_data(&self) -> Option; + /// If this node is an iframe element, returns its browsing context ID. If this node is /// not an iframe element, fails. Returns None if there is no nested browsing context. fn iframe_browsing_context_id(&self) -> Option; From e1a031e447c5067a53e64c159ba97ec78b196051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Mon, 27 Aug 2018 16:29:15 +0200 Subject: [PATCH 12/38] layout: add media_data() to ServoThreadSafeLayoutNode implementation --- components/layout_thread/dom_wrapper.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 5900b912e73..6a6bed73555 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -43,8 +43,10 @@ use script::layout_exports::{LayoutCharacterDataHelpers, LayoutDocumentHelpers}; use script::layout_exports::{LayoutElementHelpers, LayoutNodeHelpers, LayoutDom, RawLayoutElementHelpers}; use script::layout_exports::NodeFlags; use script::layout_exports::PendingRestyle; -use script_layout_interface::{HTMLCanvasData, LayoutNodeType, SVGSVGData, TrustedNodeAddress}; -use script_layout_interface::{OpaqueStyleAndLayoutData, StyleData}; +use script_layout_interface::{ + HTMLCanvasData, HTMLMediaData, LayoutNodeType, OpaqueStyleAndLayoutData, SVGSVGData, StyleData, + TrustedNodeAddress, +}; use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode}; use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity}; @@ -1053,6 +1055,11 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { this.canvas_data() } + fn media_data(&self) -> Option { + let this = unsafe { self.get_jsmanaged() }; + this.media_data() + } + fn svg_data(&self) -> Option { let this = unsafe { self.get_jsmanaged() }; this.svg_data() From bdd3e2c8353ccd58846b74238de6f4cee28d3c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Mon, 27 Aug 2018 16:01:03 +0200 Subject: [PATCH 13/38] layout: handle MediaFragmentInfo --- components/layout/fragment.rs | 52 +++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 65fd277fdde..dce5be4e403 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -31,9 +31,10 @@ use msg::constellation_msg::{BrowsingContextId, PipelineId}; use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder}; use range::*; -use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource}; -use script_layout_interface::SVGSVGData; use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; +use script_layout_interface::{ + HTMLCanvasData, HTMLCanvasDataSource, HTMLMediaData, HTMLMediaFrameSource, SVGSVGData, +}; use serde::ser::{Serialize, SerializeStruct, Serializer}; use servo_url::ServoUrl; use std::{f32, fmt}; @@ -182,6 +183,7 @@ pub enum SpecificFragmentInfo { Iframe(IframeFragmentInfo), Image(Box), + Media(Box), Canvas(Box), Svg(Box), @@ -219,6 +221,7 @@ impl SpecificFragmentInfo { SpecificFragmentInfo::GeneratedContent(_) | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | + SpecificFragmentInfo::Media(_) | SpecificFragmentInfo::ScannedText(_) | SpecificFragmentInfo::Svg(_) | SpecificFragmentInfo::Table | @@ -242,6 +245,7 @@ impl SpecificFragmentInfo { pub fn get_type(&self) -> &'static str { match *self { SpecificFragmentInfo::Canvas(_) => "SpecificFragmentInfo::Canvas", + SpecificFragmentInfo::Media(_) => "SpecificFragmentInfo::Media", SpecificFragmentInfo::Generic => "SpecificFragmentInfo::Generic", SpecificFragmentInfo::GeneratedContent(_) => "SpecificFragmentInfo::GeneratedContent", SpecificFragmentInfo::Iframe(_) => "SpecificFragmentInfo::Iframe", @@ -364,6 +368,27 @@ impl CanvasFragmentInfo { } } +pub struct MediaFragmentInfo { + pub frame_source: Box, +} + +// XXX +impl Clone for MediaFragmentInfo { + fn clone(&self) -> MediaFragmentInfo { + MediaFragmentInfo { + frame_source: self.frame_source.clone_boxed(), + } + } +} + +impl MediaFragmentInfo { + pub fn new(data: HTMLMediaData) -> MediaFragmentInfo { + MediaFragmentInfo { + frame_source: data.frame_source, + } + } +} + #[derive(Clone)] pub struct SvgFragmentInfo { pub dom_width: Au, @@ -834,6 +859,7 @@ impl Fragment { ) -> QuantitiesIncludedInIntrinsicInlineSizes { match self.specific { SpecificFragmentInfo::Canvas(_) | + SpecificFragmentInfo::Media(_) | SpecificFragmentInfo::Generic | SpecificFragmentInfo::GeneratedContent(_) | SpecificFragmentInfo::Iframe(_) | @@ -978,6 +1004,13 @@ impl Fragment { } else { Au(0) } + } + SpecificFragmentInfo::Media(ref info) => { + if let Some((_, width, _)) = info.frame_source.get_current_frame() { + Au::from_px(width as i32) + } else { + Au(0) + } }, SpecificFragmentInfo::Canvas(ref info) => info.dom_width, SpecificFragmentInfo::Svg(ref info) => info.dom_width, @@ -1001,6 +1034,13 @@ impl Fragment { } else { Au(0) } + } + SpecificFragmentInfo::Media(ref info) => { + if let Some((_, _, height)) = info.frame_source.get_current_frame() { + Au::from_px(height as i32) + } else { + Au(0) + } }, SpecificFragmentInfo::Canvas(ref info) => info.dom_height, SpecificFragmentInfo::Svg(ref info) => info.dom_height, @@ -1014,6 +1054,7 @@ impl Fragment { match self.specific { SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::Canvas(_) | + SpecificFragmentInfo::Media(_) | // TODO(stshine): According to the SVG spec, whether a SVG element has intrinsic // aspect ratio is determined by the `preserveAspectRatio` attribute. Since for // now SVG is far from implemented, we simply choose the default behavior that @@ -1549,6 +1590,7 @@ impl Fragment { result.union_block(&block_flow.base.intrinsic_inline_sizes) }, SpecificFragmentInfo::Image(_) | + SpecificFragmentInfo::Media(_) | SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Svg(_) => { @@ -2024,6 +2066,7 @@ impl Fragment { }, SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Image(_) | + SpecificFragmentInfo::Media(_) | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) | @@ -2115,6 +2158,7 @@ impl Fragment { SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | + SpecificFragmentInfo::Media(_) | SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) | SpecificFragmentInfo::InlineAbsolute(_) | @@ -2171,6 +2215,7 @@ impl Fragment { SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Image(_) | + SpecificFragmentInfo::Media(_) | SpecificFragmentInfo::Svg(_) => true, _ => false, } @@ -2202,6 +2247,7 @@ impl Fragment { SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | + SpecificFragmentInfo::Media(_) | SpecificFragmentInfo::Svg(_) | SpecificFragmentInfo::Generic | SpecificFragmentInfo::GeneratedContent(_) => { @@ -2530,6 +2576,7 @@ impl Fragment { SpecificFragmentInfo::GeneratedContent(_) | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | + SpecificFragmentInfo::Media(_) | SpecificFragmentInfo::ScannedText(_) | SpecificFragmentInfo::Svg(_) | SpecificFragmentInfo::Table | @@ -3057,6 +3104,7 @@ impl Fragment { SpecificFragmentInfo::GeneratedContent(_) | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | + SpecificFragmentInfo::Media(_) | SpecificFragmentInfo::ScannedText(_) | SpecificFragmentInfo::TruncatedFragment(_) | SpecificFragmentInfo::Svg(_) | From 006bef5eb5a96744b0dae1e8cc8fec2bbee0edc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Mon, 27 Aug 2018 16:32:09 +0200 Subject: [PATCH 14/38] layout: set building information for media fragment --- components/layout/display_list/builder.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index f473b98584a..8e903d2ceba 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -1999,6 +1999,22 @@ impl FragmentDisplayListBuilding for Fragment { } } }, + SpecificFragmentInfo::Media(ref fragment_info) => { + if let Some((ref image_key, _, _)) = fragment_info.frame_source.get_current_frame() + { + let base = create_base_display_item(state); + state.add_image_item( + base, + webrender_api::ImageDisplayItem { + image_key: *image_key, + stretch_size: stacking_relative_border_box.size.to_layout(), + tile_spacing: LayoutSize::zero(), + image_rendering: ImageRendering::Auto, + alpha_type: webrender_api::AlphaType::PremultipliedAlpha, + }, + ); + } + } SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => { let image_key = match canvas_fragment_info.source { CanvasFragmentSource::WebGL(image_key) => image_key, From 2d709a283bb2856e2d47c5163ac6a10cf00e2259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Wed, 29 Aug 2018 18:30:11 +0200 Subject: [PATCH 15/38] layout: instantiate SpecificFragmentInfo from node's media data --- components/layout/construct.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 36ab116d0ca..bb3c534830f 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -23,11 +23,12 @@ use floats::FloatKind; use flow::{AbsoluteDescendants, Flow, FlowClass, GetBaseFlow, ImmutableFlowUtils}; use flow::{FlowFlags, MutableFlowUtils, MutableOwnedFlowUtils}; use flow_ref::FlowRef; -use fragment::{CanvasFragmentInfo, ImageFragmentInfo, InlineAbsoluteFragmentInfo, SvgFragmentInfo}; -use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo, FragmentFlags}; -use fragment::{InlineAbsoluteHypotheticalFragmentInfo, TableColumnFragmentInfo}; -use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo}; -use fragment::WhitespaceStrippingResult; +use fragment::{ + CanvasFragmentInfo, Fragment, FragmentFlags, GeneratedContentInfo, IframeFragmentInfo, + ImageFragmentInfo, InlineAbsoluteFragmentInfo, InlineAbsoluteHypotheticalFragmentInfo, + InlineBlockFragmentInfo, MediaFragmentInfo, SpecificFragmentInfo, SvgFragmentInfo, + TableColumnFragmentInfo, UnscannedTextFragmentInfo, WhitespaceStrippingResult, +}; use inline::{InlineFlow, InlineFragmentNodeInfo, InlineFragmentNodeFlags}; use linked_list::prepend_from; use list_item::{ListItemFlow, ListStyleTypeContent}; @@ -405,6 +406,10 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode> &self.layout_context, )); SpecificFragmentInfo::Image(image_info) + } + Some(LayoutNodeType::Element(LayoutElementType::HTMLMediaElement)) => { + let data = node.media_data().unwrap(); + SpecificFragmentInfo::Media(Box::new(MediaFragmentInfo::new(data))) }, Some(LayoutNodeType::Element(LayoutElementType::HTMLObjectElement)) => { let image_info = Box::new(ImageFragmentInfo::new( @@ -1956,6 +1961,7 @@ where match self.type_id() { Some(LayoutNodeType::Text) | Some(LayoutNodeType::Element(LayoutElementType::HTMLImageElement)) | + Some(LayoutNodeType::Element(LayoutElementType::HTMLMediaElement)) | Some(LayoutNodeType::Element(LayoutElementType::HTMLIFrameElement)) | Some(LayoutNodeType::Element(LayoutElementType::HTMLCanvasElement)) | Some(LayoutNodeType::Element(LayoutElementType::SVGSVGElement)) => true, From 1f406ef0a0f302ca1741dbaa59887a0c1c924865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 31 Aug 2018 11:53:22 +0200 Subject: [PATCH 16/38] Player does not need to go inside a mutexed Arc --- components/script/dom/htmlmediaelement.rs | 34 +++++++++-------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 4aaad2986fc..3cd79cb4563 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -52,7 +52,7 @@ use std::sync::{Arc, Mutex}; use task_source::{TaskSource, TaskSourceName}; use time::{self, Timespec, Duration}; -unsafe_no_jsmanaged_fields!(Arc>>); +unsafe_no_jsmanaged_fields!(Player); unsafe_no_jsmanaged_fields!(MediaFrameRenderer); #[dom_struct] @@ -91,7 +91,7 @@ pub struct HTMLMediaElement { /// Whether the media metadata has been completely received. have_metadata: Cell, #[ignore_malloc_size_of = "servo_media"] - player: Arc>>, + player: Box, #[ignore_malloc_size_of = "oops"] frame_renderer: MediaFrameRenderer, } @@ -135,9 +135,7 @@ impl HTMLMediaElement { pending_play_promises: Default::default(), in_flight_play_promises_queue: Default::default(), have_metadata: Cell::new(false), - player: Arc::new(Mutex::new( - ServoMedia::get().unwrap().create_player().unwrap(), - )), + player: ServoMedia::get().unwrap().create_player().unwrap(), frame_renderer: MediaFrameRenderer::new(document.window().get_webrender_api_sender()), } } @@ -235,7 +233,7 @@ impl HTMLMediaElement { } this.fulfill_in_flight_play_promises(|| { - this.player.lock().unwrap().play(); + this.player.play(); }); }), window.upcast(), @@ -283,7 +281,7 @@ impl HTMLMediaElement { this.upcast::().fire_event(atom!("pause")); //FIXME(victor) - //this.player.lock().unwrap().pause(); + //this.player.pause(); // Step 2.3.3. // Done after running this closure in @@ -320,7 +318,7 @@ impl HTMLMediaElement { this.fulfill_in_flight_play_promises(|| { // Step 2.1. this.upcast::().fire_event(atom!("playing")); - this.player.lock().unwrap().play(); + this.player.play(); // Step 2.2. // Done after running this closure in @@ -672,7 +670,7 @@ impl HTMLMediaElement { // Step 5. this.upcast::().fire_event(atom!("error")); - this.player.lock().unwrap().stop(); + this.player.stop(); // Step 6. // Done after running this closure in @@ -837,15 +835,10 @@ impl HTMLMediaElement { fn setup_media_player(&self) { let (action_sender, action_receiver) = ipc::channel().unwrap(); - self.player - .lock() - .unwrap() - .register_event_handler(action_sender); - self.player - .lock() - .unwrap() - .register_frame_renderer(Arc::new(self.frame_renderer.clone())); - self.player.lock().unwrap().setup().unwrap(); + self.player.register_event_handler(action_sender); + self.player.register_frame_renderer(Arc::new(self.frame_renderer.clone())); + // XXXferjm this can fail. + self.player.setup().unwrap(); let trusted_node = Trusted::new(self); let window = window_from_node(self); @@ -1132,7 +1125,7 @@ impl FetchResponseListener for HTMLMediaElementContext { let elem = self.elem.root(); // push input data into the player - if let Err(_) = elem.player.lock().unwrap().push_data(payload) { + if let Err(_) = elem.player.push_data(payload) { eprintln!("Couldn't push input data to player"); } @@ -1156,10 +1149,9 @@ impl FetchResponseListener for HTMLMediaElementContext { return; } let elem = self.elem.root(); - let player = elem.player.lock().unwrap(); // signal the eos to player - if let Err(_) = player.end_of_stream() { + if let Err(_) = elem.player.end_of_stream() { eprintln!("Couldn't signal EOS to player"); } From 8c40ef459b8ee58f480128f9e9ed3a7b3fd6f500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 31 Aug 2018 17:41:23 +0200 Subject: [PATCH 17/38] Do not share entire FrameRenderer with layout, only current frame --- Cargo.lock | 28 +++--- Cargo.toml | 2 + components/layout/display_list/builder.rs | 2 +- components/layout/fragment.rs | 22 ++--- components/script/dom/htmlmediaelement.rs | 90 ++++++++++++++++--- components/script/dom/mediaframerenderer.rs | 98 --------------------- components/script/dom/mod.rs | 1 - components/script_layout_interface/lib.rs | 8 +- 8 files changed, 102 insertions(+), 149 deletions(-) delete mode 100644 components/script/dom/mediaframerenderer.rs diff --git a/Cargo.lock b/Cargo.lock index 8c7da7e5584..fc7cf588e38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2992,7 +2992,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=framerenderer)", "servo_allocator 0.0.1", "servo_arc 0.1.1", "servo_atoms 0.0.1", @@ -3226,9 +3226,9 @@ name = "servo-media" version = "0.1.0" source = "git+https://github.com/servo/media#e700a0834c3f38d49890d846591fd699e7405a48" 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=framerenderer)", + "servo-media-gstreamer 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)", + "servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)", ] [[package]] @@ -3243,7 +3243,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=framerenderer)", "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3260,8 +3260,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=framerenderer)", + "servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)", "zip 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4545,14 +4545,14 @@ dependencies = [ "checksum serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "5c508584d9913df116b91505eec55610a2f5b16e9ed793c46e4d0152872b3e74" "checksum servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21069a884c33fe6ee596975e1f3849ed88c4ec857fbaf11d33672d8ebe051217" "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-fontconfig-sys 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa080856db55f188aaf36f01cae8c03448a6056552adb77d461179e44e1a14" +"checksum servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9232032c2e85118c0282c6562c84cab12316e655491ba0a5d1905b2320060d1b" +"checksum servo-media 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)" = "" +"checksum servo-media-audio 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)" = "" +"checksum servo-media-gstreamer 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)" = "" +"checksum servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)" = "" "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=framerenderer)" = "" "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..d4af6793704 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 = "framerenderer" } diff --git a/components/layout/display_list/builder.rs b/components/layout/display_list/builder.rs index 8e903d2ceba..3d49fdbb61c 100644 --- a/components/layout/display_list/builder.rs +++ b/components/layout/display_list/builder.rs @@ -2000,7 +2000,7 @@ impl FragmentDisplayListBuilding for Fragment { } }, SpecificFragmentInfo::Media(ref fragment_info) => { - if let Some((ref image_key, _, _)) = fragment_info.frame_source.get_current_frame() + if let Some((ref image_key, _, _)) = fragment_info.current_frame { let base = create_base_display_item(state); state.add_image_item( diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index dce5be4e403..f79dcc8d3d0 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -32,9 +32,7 @@ use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder}; use range::*; use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; -use script_layout_interface::{ - HTMLCanvasData, HTMLCanvasDataSource, HTMLMediaData, HTMLMediaFrameSource, SVGSVGData, -}; +use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource, HTMLMediaData, SVGSVGData}; use serde::ser::{Serialize, SerializeStruct, Serializer}; use servo_url::ServoUrl; use std::{f32, fmt}; @@ -368,23 +366,15 @@ impl CanvasFragmentInfo { } } +#[derive(Clone)] pub struct MediaFragmentInfo { - pub frame_source: Box, -} - -// XXX -impl Clone for MediaFragmentInfo { - fn clone(&self) -> MediaFragmentInfo { - MediaFragmentInfo { - frame_source: self.frame_source.clone_boxed(), - } - } + pub current_frame: Option<(webrender_api::ImageKey, i32, i32)>, } impl MediaFragmentInfo { pub fn new(data: HTMLMediaData) -> MediaFragmentInfo { MediaFragmentInfo { - frame_source: data.frame_source, + current_frame: data.current_frame, } } } @@ -1006,7 +996,7 @@ impl Fragment { } } SpecificFragmentInfo::Media(ref info) => { - if let Some((_, width, _)) = info.frame_source.get_current_frame() { + if let Some((_, width, _)) = info.current_frame { Au::from_px(width as i32) } else { Au(0) @@ -1036,7 +1026,7 @@ impl Fragment { } } SpecificFragmentInfo::Media(ref info) => { - if let Some((_, _, height)) = info.frame_source.get_current_frame() { + if let Some((_, _, height)) = info.current_frame { Au::from_px(height as i32) } else { Au(0) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 3cd79cb4563..fc946217a8e 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -26,7 +26,6 @@ use dom::eventtarget::EventTarget; use dom::htmlelement::HTMLElement; use dom::htmlsourceelement::HTMLSourceElement; use dom::mediaerror::MediaError; -use dom::mediaframerenderer::MediaFrameRenderer; use dom::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindContext}; use dom::promise::Promise; use dom::virtualmethods::VirtualMethods; @@ -42,6 +41,7 @@ use network_listener::{NetworkListener, PreInvoke}; use script_layout_interface::HTMLMediaData; use script_thread::ScriptThread; use servo_media::player::{PlaybackState, Player, PlayerEvent}; +use servo_media::player::frame::{Frame, FrameRenderer}; use servo_media::ServoMedia; use servo_url::ServoUrl; use std::cell::Cell; @@ -51,9 +51,77 @@ use std::rc::Rc; use std::sync::{Arc, Mutex}; use task_source::{TaskSource, TaskSourceName}; use time::{self, Timespec, Duration}; +use webrender_api::{ImageData, ImageDescriptor, ImageFormat, ImageKey, RenderApi}; +use webrender_api::{RenderApiSender, Transaction}; unsafe_no_jsmanaged_fields!(Player); -unsafe_no_jsmanaged_fields!(MediaFrameRenderer); +unsafe_no_jsmanaged_fields!(Mutex); + +struct MediaFrameRenderer { + api: RenderApi, + current_frame: Option<(ImageKey, i32, i32)>, + old_frame: Option, + very_old_frame: Option, +} + +impl MediaFrameRenderer { + fn new(render_api_sender: RenderApiSender) -> Self { + Self { + api: render_api_sender.create_api(), + current_frame: None, + old_frame: None, + very_old_frame: None, + } + } +} + +impl FrameRenderer for MediaFrameRenderer { + fn render(&mut self, frame: Frame) { + let descriptor = ImageDescriptor::new( + frame.get_width() as u32, + frame.get_height() as u32, + ImageFormat::BGRA8, + false, + false, + ); + + let mut txn = Transaction::new(); + + let image_data = ImageData::Raw(frame.get_data().clone()); + + if let Some(old_image_key) = mem::replace(&mut self.very_old_frame, self.old_frame.take()) { + txn.delete_image(old_image_key); + } + + match self.current_frame { + Some((ref image_key, ref mut width, ref mut height)) + if *width == frame.get_width() && *height == frame.get_height() => + { + txn.update_image(*image_key, descriptor, image_data, None); + + if let Some(old_image_key) = self.old_frame.take() { + txn.delete_image(old_image_key); + } + } + Some((ref mut image_key, ref mut width, ref mut height)) => { + self.old_frame = Some(*image_key); + + let new_image_key = self.api.generate_image_key(); + txn.add_image(new_image_key, descriptor, image_data, None); + *image_key = new_image_key; + *width = frame.get_width(); + *height = frame.get_height(); + } + None => { + let image_key = self.api.generate_image_key(); + txn.add_image(image_key, descriptor, image_data, None); + self.current_frame = Some((image_key, frame.get_width(), frame.get_height())); + } + } + + self.api.update_resources(txn.resource_updates); + } +} #[dom_struct] // FIXME(nox): A lot of tasks queued for this element should probably be in the @@ -92,8 +160,8 @@ pub struct HTMLMediaElement { have_metadata: Cell, #[ignore_malloc_size_of = "servo_media"] player: Box, - #[ignore_malloc_size_of = "oops"] - frame_renderer: MediaFrameRenderer, + #[ignore_malloc_size_of = "Arc"] + frame_renderer: Arc>, } /// @@ -136,7 +204,8 @@ impl HTMLMediaElement { in_flight_play_promises_queue: Default::default(), have_metadata: Cell::new(false), player: ServoMedia::get().unwrap().create_player().unwrap(), - frame_renderer: MediaFrameRenderer::new(document.window().get_webrender_api_sender()), + frame_renderer: + Arc::new(Mutex::new(MediaFrameRenderer::new(document.window().get_webrender_api_sender()))), } } @@ -836,7 +905,7 @@ impl HTMLMediaElement { let (action_sender, action_receiver) = ipc::channel().unwrap(); self.player.register_event_handler(action_sender); - self.player.register_frame_renderer(Arc::new(self.frame_renderer.clone())); + self.player.register_frame_renderer(self.frame_renderer.clone()); // XXXferjm this can fail. self.player.setup().unwrap(); @@ -1026,12 +1095,9 @@ pub trait LayoutHTMLMediaElementHelpers { impl LayoutHTMLMediaElementHelpers for LayoutDom { #[allow(unsafe_code)] fn data(&self) -> HTMLMediaData { - unsafe { - let media = &*self.unsafe_get(); - - HTMLMediaData { - frame_source: Box::new(media.frame_renderer.clone()), - } + let media = unsafe { &*self.unsafe_get() }; + HTMLMediaData { + current_frame: media.frame_renderer.lock().unwrap().current_frame.clone(), } } } diff --git a/components/script/dom/mediaframerenderer.rs b/components/script/dom/mediaframerenderer.rs deleted file mode 100644 index 28a52c4bf7f..00000000000 --- a/components/script/dom/mediaframerenderer.rs +++ /dev/null @@ -1,98 +0,0 @@ -use servo_media::player::frame::{Frame, FrameRenderer}; -use script_layout_interface::HTMLMediaFrameSource; -use std::mem; -use std::sync::{Arc, Mutex}; -use webrender_api::{ - ImageData, ImageDescriptor, ImageFormat, ImageKey, RenderApi, RenderApiSender, Transaction, -}; - -#[derive(Clone)] -pub struct MediaFrameRenderer { - inner: Arc>, -} - -impl MediaFrameRenderer { - pub fn new(render_api_sender: RenderApiSender) -> MediaFrameRenderer { - MediaFrameRenderer { - inner: Arc::new(Mutex::new(MediaFrameRendererInner { - api: render_api_sender.create_api(), - current_frame: None, - old_frame: None, - very_old_frame: None, - })), - } - } -} - -impl FrameRenderer for MediaFrameRenderer { - fn render(&self, frame: Frame) { - self.inner.lock().unwrap().render(frame); - } -} - -impl HTMLMediaFrameSource for MediaFrameRenderer { - fn get_current_frame(&self) -> Option<(ImageKey, i32, i32)> { - let inner = self.inner.lock().unwrap(); - inner.current_frame.clone() - } - - fn clone_boxed(&self) -> Box { - Box::new(self.clone()) - } -} - -struct MediaFrameRendererInner { - api: RenderApi, - current_frame: Option<(ImageKey, i32, i32)>, - old_frame: Option, - very_old_frame: Option, -} - -impl MediaFrameRendererInner { - fn render(&mut self, frame: Frame) { - let descriptor = ImageDescriptor::new( - frame.get_width() as u32, - frame.get_height() as u32, - ImageFormat::BGRA8, - false, - false, - ); - - let mut txn = Transaction::new(); - - //let image_data = ImageData::new_shared(frame.get_data().clone()); - let image_data = ImageData::Raw(frame.get_data().clone()); - - if let Some(old_image_key) = mem::replace(&mut self.very_old_frame, self.old_frame.take()) { - txn.delete_image(old_image_key); - } - - match self.current_frame { - Some((ref image_key, ref mut width, ref mut height)) - if *width == frame.get_width() && *height == frame.get_height() => - { - txn.update_image(*image_key, descriptor, image_data, None); - - if let Some(old_image_key) = self.old_frame.take() { - txn.delete_image(old_image_key); - } - } - Some((ref mut image_key, ref mut width, ref mut height)) => { - self.old_frame = Some(*image_key); - - let new_image_key = self.api.generate_image_key(); - txn.add_image(new_image_key, descriptor, image_data, None); - *image_key = new_image_key; - *width = frame.get_width(); - *height = frame.get_height(); - } - None => { - let image_key = self.api.generate_image_key(); - txn.add_image(image_key, descriptor, image_data, None); - self.current_frame = Some((image_key, frame.get_width(), frame.get_height())); - } - } - - self.api.update_resources(txn.resource_updates); - } -} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 10ed49f99a2..07425cccae1 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -390,7 +390,6 @@ pub mod inputevent; pub mod keyboardevent; pub mod location; pub mod mediaerror; -pub mod mediaframerenderer; pub mod medialist; pub mod mediaquerylist; pub mod mediaquerylistevent; diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index 0db0bbe3ef5..bd48b2b7c51 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -172,12 +172,6 @@ pub struct PendingImage { pub id: PendingImageId, } -/// FIXME(victor): probably this doesn't belong here -pub trait HTMLMediaFrameSource: Send + Sync + 'static { - fn get_current_frame(&self) -> Option<(webrender_api::ImageKey, i32, i32)>; - fn clone_boxed(&self) -> Box; -} - pub struct HTMLMediaData { - pub frame_source: Box, + pub current_frame: Option<(webrender_api::ImageKey, i32, i32)>, } From 72b1df343e49916a6047070d5c855a652fb52072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 31 Aug 2018 18:31:29 +0200 Subject: [PATCH 18/38] Move unsafe_no_jsmanaged_fields to trace --- components/script/dom/bindings/trace.rs | 9 +++++++-- components/script/dom/htmlmediaelement.rs | 5 +---- components/script/dom/window.rs | 12 +----------- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index a3c4c7814ea..a625de741ab 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -48,6 +48,7 @@ use dom::bindings::str::{DOMString, USVString}; use dom::bindings::utils::WindowProxyHandler; use dom::document::PendingRestyle; use dom::htmlimageelement::SourceSet; +use dom::htmlmediaelement::MediaFrameRenderer; use encoding_rs::{Decoder, Encoding}; use euclid::{Transform2D, Transform3D, Point2D, Vector2D, Rect, TypedSize2D, TypedScale}; use euclid::Length as EuclidLength; @@ -96,6 +97,7 @@ use servo_media::audio::context::AudioContext; use servo_media::audio::graph::NodeId; use servo_media::audio::panner_node::{DistanceModel, PanningModel}; use servo_media::audio::param::ParamType; +use servo_media::player::Player; use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl}; use smallvec::SmallVec; use std::cell::{Cell, RefCell, UnsafeCell}; @@ -104,7 +106,7 @@ use std::hash::{BuildHasher, Hash}; use std::ops::{Deref, DerefMut}; use std::path::PathBuf; use std::rc::Rc; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::time::{SystemTime, Instant}; use style::attr::{AttrIdentifier, AttrValue, LengthOrPercentageOrAuto}; @@ -121,7 +123,7 @@ use style::stylesheets::keyframes_rule::Keyframe; use style::values::specified::Length; use time::Duration; use uuid::Uuid; -use webrender_api::{DocumentId, ImageKey}; +use webrender_api::{DocumentId, ImageKey, RenderApiSender}; use webvr_traits::WebVRGamepadHand; /// A trait to allow tracing (only) DOM objects. @@ -454,6 +456,9 @@ unsafe_no_jsmanaged_fields!(AudioBuffer); unsafe_no_jsmanaged_fields!(AudioContext); unsafe_no_jsmanaged_fields!(NodeId); unsafe_no_jsmanaged_fields!(AnalysisEngine, DistanceModel, PanningModel, ParamType); +unsafe_no_jsmanaged_fields!(Player); +unsafe_no_jsmanaged_fields!(Mutex); +unsafe_no_jsmanaged_fields!(RenderApiSender); unsafe impl<'a> JSTraceable for &'a str { #[inline] diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index fc946217a8e..5c623044574 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -54,10 +54,7 @@ use time::{self, Timespec, Duration}; use webrender_api::{ImageData, ImageDescriptor, ImageFormat, ImageKey, RenderApi}; use webrender_api::{RenderApiSender, Transaction}; -unsafe_no_jsmanaged_fields!(Player); -unsafe_no_jsmanaged_fields!(Mutex); - -struct MediaFrameRenderer { +pub struct MediaFrameRenderer { api: RenderApi, current_frame: Option<(ImageKey, i32, i32)>, old_frame: Option, diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index b6c7a460103..c50aae0aec7 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -132,9 +132,7 @@ use time; use timers::{IsInterval, TimerCallback}; use url::Position; use webdriver_handlers::jsval_to_webdriver; -use webrender_api::{ - DeviceIntPoint, DeviceUintSize, DocumentId, ExternalScrollId, RenderApiSender, -}; +use webrender_api::{DeviceIntPoint, DeviceUintSize, DocumentId, ExternalScrollId, RenderApiSender}; use webvr_traits::WebVRMsg; /// Current state of the window object @@ -315,14 +313,6 @@ pub struct Window { webrender_api_sender: RenderApiSender, } -// FIXME(victor): this doesn't belong here -#[allow(unsafe_code)] -unsafe impl ::dom::bindings::trace::JSTraceable for RenderApiSender { - unsafe fn trace(&self, _trc: *mut ::js::jsapi::JSTracer) { - // Do nothing - } -} - impl Window { pub fn get_exists_mut_observer(&self) -> bool { self.exists_mut_observer.get() From 3fbeb398d4439a83e1c4566908adfec7b42f09a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 4 Sep 2018 09:23:26 +0200 Subject: [PATCH 19/38] Revert import style format --- components/layout/construct.rs | 10 ++++------ components/layout_thread/dom_wrapper.rs | 6 ++---- components/script/dom/node.rs | 6 ++---- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/components/layout/construct.rs b/components/layout/construct.rs index bb3c534830f..ba86416f935 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -23,12 +23,10 @@ use floats::FloatKind; use flow::{AbsoluteDescendants, Flow, FlowClass, GetBaseFlow, ImmutableFlowUtils}; use flow::{FlowFlags, MutableFlowUtils, MutableOwnedFlowUtils}; use flow_ref::FlowRef; -use fragment::{ - CanvasFragmentInfo, Fragment, FragmentFlags, GeneratedContentInfo, IframeFragmentInfo, - ImageFragmentInfo, InlineAbsoluteFragmentInfo, InlineAbsoluteHypotheticalFragmentInfo, - InlineBlockFragmentInfo, MediaFragmentInfo, SpecificFragmentInfo, SvgFragmentInfo, - TableColumnFragmentInfo, UnscannedTextFragmentInfo, WhitespaceStrippingResult, -}; +use fragment::{CanvasFragmentInfo, Fragment, FragmentFlags, GeneratedContentInfo, IframeFragmentInfo}; +use fragment::{ImageFragmentInfo, InlineAbsoluteFragmentInfo, InlineAbsoluteHypotheticalFragmentInfo}; +use fragment::{InlineBlockFragmentInfo, MediaFragmentInfo, SpecificFragmentInfo, SvgFragmentInfo}; +use fragment::{TableColumnFragmentInfo, UnscannedTextFragmentInfo, WhitespaceStrippingResult}; use inline::{InlineFlow, InlineFragmentNodeInfo, InlineFragmentNodeFlags}; use linked_list::prepend_from; use list_item::{ListItemFlow, ListStyleTypeContent}; diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 6a6bed73555..3c3495ee6fe 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -43,10 +43,8 @@ use script::layout_exports::{LayoutCharacterDataHelpers, LayoutDocumentHelpers}; use script::layout_exports::{LayoutElementHelpers, LayoutNodeHelpers, LayoutDom, RawLayoutElementHelpers}; use script::layout_exports::NodeFlags; use script::layout_exports::PendingRestyle; -use script_layout_interface::{ - HTMLCanvasData, HTMLMediaData, LayoutNodeType, OpaqueStyleAndLayoutData, SVGSVGData, StyleData, - TrustedNodeAddress, -}; +use script_layout_interface::{HTMLCanvasData, HTMLMediaData, LayoutNodeType, OpaqueStyleAndLayoutData}; +use script_layout_interface::{SVGSVGData, StyleData, TrustedNodeAddress}; use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode}; use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity}; diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 0c48d3d2df3..43fe454bc7f 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -64,10 +64,8 @@ use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use msg::constellation_msg::{BrowsingContextId, PipelineId}; use ref_slice::ref_slice; use script_layout_interface::message::Msg; -use script_layout_interface::{ - HTMLCanvasData, HTMLMediaData, LayoutElementType, LayoutNodeType, OpaqueStyleAndLayoutData, - SVGSVGData, TrustedNodeAddress, -}; +use script_layout_interface::{HTMLCanvasData, HTMLMediaData, LayoutElementType, LayoutNodeType}; +use script_layout_interface::{OpaqueStyleAndLayoutData, SVGSVGData, TrustedNodeAddress}; use script_thread::ScriptThread; use script_traits::DocumentActivity; use script_traits::UntrustedNodeAddress; From c1bd551b111ac300f6edac91e6bf6cf3658661af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 4 Sep 2018 09:37:29 +0200 Subject: [PATCH 20/38] Clarify some FIXMEs and bail out if we fail pushing data to player --- components/script/dom/htmlmediaelement.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 5c623044574..db4c1c43d82 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -602,7 +602,7 @@ impl HTMLMediaElement { }, Mode::Children(_source) => { // Step 9.children. - // FIXME(victor): seems not implemeted yet + // FIXME: https://github.com/servo/servo/issues/21481 self.queue_dedicated_media_source_failure_steps() }, } @@ -1187,9 +1187,10 @@ impl FetchResponseListener for HTMLMediaElementContext { let elem = self.elem.root(); - // push input data into the player + // Push input data into the player. if let Err(_) = elem.player.push_data(payload) { eprintln!("Couldn't push input data to player"); + return; } // https://html.spec.whatwg.org/multipage/#concept-media-load-resource step 4, @@ -1213,7 +1214,7 @@ impl FetchResponseListener for HTMLMediaElementContext { } let elem = self.elem.root(); - // signal the eos to player + // Signal the eos to player. if let Err(_) = elem.player.end_of_stream() { eprintln!("Couldn't signal EOS to player"); } @@ -1221,9 +1222,17 @@ impl FetchResponseListener for HTMLMediaElementContext { // => "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 !elem.have_metadata.get() { - // FIXME(victor): adjust player's max-size (or buffering) + // FIXME(victor): adjust player's max-size (or buffering). + // + // In short streams the EOS might arrive before extracting the stream + // metadata. This is because the internal queue in the GStreamer appsrc element, + // has a size of 200K and it pushes the data until it is reached. It would be nice + // to add a property to set the max-data in appsrc according to reported size of + // the stream. + // Until then, we comment out the failure steps. + // //elem.queue_dedicated_media_source_failure_steps(); - // => "Once the entire media resource has been fetched..." + // => "Once the entire media resource has been fetched..." } else if status.is_ok() { elem.change_ready_state(ReadyState::HaveEnoughData); From 468c59a217598f7da323c1c3c3479c4e3a59d2d4 Mon Sep 17 00:00:00 2001 From: Fernando Jimenez Moreno Date: Fri, 7 Sep 2018 18:47:33 +0200 Subject: [PATCH 21/38] Abort in-progress fetching process during load algorithm --- components/script/dom/htmlmediaelement.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index db4c1c43d82..51d9d44b597 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -30,12 +30,14 @@ use dom::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindCo use dom::promise::Promise; use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; +use fetch::FetchCanceller; use html5ever::{LocalName, Prefix}; use ipc_channel::ipc; use ipc_channel::router::ROUTER; use microtask::{Microtask, MicrotaskRunnable}; use mime::{Mime, SubLevel, TopLevel}; -use net_traits::{FetchResponseListener, FetchMetadata, Metadata, NetworkError}; +use net_traits::{CoreResourceMsg, FetchChannels, FetchResponseListener, FetchMetadata, Metadata}; +use net_traits::NetworkError; use net_traits::request::{CredentialsMode, Destination, RequestInit}; use network_listener::{NetworkListener, PreInvoke}; use script_layout_interface::HTMLMediaData; @@ -159,6 +161,7 @@ pub struct HTMLMediaElement { player: Box, #[ignore_malloc_size_of = "Arc"] frame_renderer: Arc>, + fetch_canceller: DomRefCell, } /// @@ -203,6 +206,7 @@ impl HTMLMediaElement { player: ServoMedia::get().unwrap().create_player().unwrap(), frame_renderer: Arc::new(Mutex::new(MediaFrameRenderer::new(document.window().get_webrender_api_sender()))), + fetch_canceller: DomRefCell::new(Default::default()), } } @@ -689,9 +693,10 @@ impl HTMLMediaElement { listener.notify_fetch(message.to().unwrap()); }), ); - document - .loader_mut() - .fetch_async_background(request, action_sender); + 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(); }, Resource::Object => { // FIXME(nox): Actually do something with the object. @@ -779,7 +784,7 @@ impl HTMLMediaElement { task_source.queue_simple_event(self.upcast(), atom!("emptied"), &window); // Step 6.2. - // FIXME(nox): Abort in-progress fetching process. + self.fetch_canceller.borrow_mut().cancel(); // Step 6.3. // FIXME(nox): Detach MediaSource media provider object. From 8fd9b72eb7c93cb0334a8ad0261828da72b6eef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 12 Sep 2018 13:36:16 +0200 Subject: [PATCH 22/38] Add show poster flag --- components/script/dom/htmlmediaelement.rs | 26 ++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 51d9d44b597..55d0a24cb47 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -162,6 +162,8 @@ pub struct HTMLMediaElement { #[ignore_malloc_size_of = "Arc"] frame_renderer: Arc>, fetch_canceller: DomRefCell, + /// https://html.spec.whatwg.org/multipage/media.html#show-poster-flag + show_poster: Cell, } /// @@ -207,6 +209,7 @@ impl HTMLMediaElement { frame_renderer: Arc::new(Mutex::new(MediaFrameRenderer::new(document.window().get_webrender_api_sender()))), fetch_canceller: DomRefCell::new(Default::default()), + show_poster: Cell::new(true), } } @@ -272,8 +275,10 @@ impl HTMLMediaElement { self.paused.set(false); // Step 6.2. - // FIXME(nox): Set show poster flag to false and run time marches on - // steps if show poster flag is true. + if self.show_poster.get() { + self.show_poster.set(false); + self.time_marches_on(); + } // Step 6.3. task_source.queue_simple_event(self.upcast(), atom!("play"), &window); @@ -317,6 +322,11 @@ impl HTMLMediaElement { // Not applicable here, the promise is returned from Play. } + /// https://html.spec.whatwg.org/multipage/media.html#time-marches-on + fn time_marches_on(&self) { + // TODO: implement this. + } + /// fn internal_pause_steps(&self) { // Step 1. @@ -468,7 +478,11 @@ impl HTMLMediaElement { if self.autoplaying.get() && self.Paused() && self.Autoplay() { // Step 1 self.paused.set(false); - // TODO step 2: show poster + // Step 2 + if self.show_poster.get() { + self.show_poster.set(false); + self.time_marches_on(); + } // Step 3 task_source.queue_simple_event(self.upcast(), atom!("play"), &window); // Step 4 @@ -489,7 +503,7 @@ impl HTMLMediaElement { self.network_state.set(NetworkState::NoSource); // Step 2. - // FIXME(nox): Set show poster flag to true. + self.show_poster.set(true); // Step 3. self.delay_load_event(true); @@ -517,6 +531,8 @@ impl HTMLMediaElement { // https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm fn resource_selection_algorithm_sync(&self, base_url: ServoUrl) { // Step 5. + // FIXME(ferjm): Implement blocked_on_parser logic + // https://html.spec.whatwg.org/multipage/media.html#blocked-on-parser // FIXME(nox): Maybe populate the list of pending text tracks. // Step 6. @@ -736,7 +752,7 @@ impl HTMLMediaElement { this.network_state.set(NetworkState::NoSource); // Step 4. - // FIXME(nox): Set show poster flag to true. + this.show_poster.set(true); // Step 5. this.upcast::().fire_event(atom!("error")); From b656ae195fc0784e9582e4fe7a19eddaba2debf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 13 Sep 2018 14:15:31 +0200 Subject: [PATCH 23/38] Player pause --- Cargo.lock | 24 +++++++++++------------ Cargo.toml | 2 -- components/script/dom/htmlmediaelement.rs | 3 +-- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc7cf588e38..f07221dd8a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2992,7 +2992,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=framerenderer)", + "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", @@ -3226,9 +3226,9 @@ name = "servo-media" version = "0.1.0" source = "git+https://github.com/servo/media#e700a0834c3f38d49890d846591fd699e7405a48" dependencies = [ - "servo-media-audio 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)", - "servo-media-gstreamer 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)", - "servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)", + "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]] @@ -3243,7 +3243,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=framerenderer)", + "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)", ] @@ -3260,8 +3260,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=framerenderer)", - "servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)", + "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)", ] @@ -4547,12 +4547,12 @@ dependencies = [ "checksum servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93f799b649b4a2bf362398910eca35240704c7e765e780349b2bb1070d892262" "checksum servo-fontconfig-sys 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa080856db55f188aaf36f01cae8c03448a6056552adb77d461179e44e1a14" "checksum servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9232032c2e85118c0282c6562c84cab12316e655491ba0a5d1905b2320060d1b" -"checksum servo-media 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)" = "" -"checksum servo-media-audio 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)" = "" -"checksum servo-media-gstreamer 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)" = "" -"checksum servo-media-player 0.1.0 (git+https://github.com/ferjm/media?branch=framerenderer)" = "" +"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=framerenderer)" = "" +"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 d4af6793704..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 = "framerenderer" } diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 55d0a24cb47..311f1ed779c 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -360,8 +360,7 @@ impl HTMLMediaElement { // Step 2.3.2. this.upcast::().fire_event(atom!("pause")); - //FIXME(victor) - //this.player.pause(); + this.player.pause(); // Step 2.3.3. // Done after running this closure in From da0e92d7f830b4f1e09d9e3099ae39cf2b62fd10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 20 Sep 2018 17:06:02 +0200 Subject: [PATCH 24/38] Cancel fetch in some media data processing steps --- components/script/dom/htmlmediaelement.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 311f1ed779c..60ba9632285 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -1193,9 +1193,9 @@ impl FetchResponseListener for HTMLMediaElementContext { // Ensure that the element doesn't receive any further notifications // of the aborted fetch. self.ignore_response = true; - self.elem - .root() - .queue_dedicated_media_source_failure_steps(); + let elem = self.elem.root(); + elem.fetch_canceller.borrow_mut().cancel(); + elem.queue_dedicated_media_source_failure_steps(); } } @@ -1264,6 +1264,9 @@ impl FetchResponseListener for HTMLMediaElementContext { } // => "If the connection is interrupted after some media data has been received..." else if elem.ready_state.get() != ReadyState::HaveNothing { + // Step 1 + elem.fetch_canceller.borrow_mut().cancel(); + // Step 2 elem.error.set(Some(&*MediaError::new( &*window_from_node(&*elem), From 6904535865c3d7edebfdfc5919bc9207013d4cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 21 Sep 2018 11:26:37 +0200 Subject: [PATCH 25/38] videoWidth and videoHeight params --- components/atoms/static_atoms.txt | 1 + components/script/dom/htmlmediaelement.rs | 38 +++++++++++++++++-- components/script/dom/htmlvideoelement.rs | 32 +++++++++++++++- .../dom/webidls/HTMLVideoElement.webidl | 4 +- 4 files changed, 69 insertions(+), 6 deletions(-) diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt index 7fbd043dc0f..151ad41d914 100644 --- a/components/atoms/static_atoms.txt +++ b/components/atoms/static_atoms.txt @@ -65,6 +65,7 @@ range readystatechange reftest-wait reset +resize right rtl sans-serif diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 60ba9632285..605b6cd8a99 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -25,6 +25,7 @@ use dom::element::{Element, AttributeMutation}; use dom::eventtarget::EventTarget; use dom::htmlelement::HTMLElement; use dom::htmlsourceelement::HTMLSourceElement; +use dom::htmlvideoelement::HTMLVideoElement; use dom::mediaerror::MediaError; use dom::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindContext}; use dom::promise::Promise; @@ -177,9 +178,9 @@ pub enum NetworkState { } /// -#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq, PartialOrd)] #[repr(u8)] -enum ReadyState { +pub enum ReadyState { HaveNothing = HTMLMediaElementConstants::HAVE_NOTHING as u8, HaveMetadata = HTMLMediaElementConstants::HAVE_METADATA as u8, HaveCurrentData = HTMLMediaElementConstants::HAVE_CURRENT_DATA as u8, @@ -213,6 +214,10 @@ impl HTMLMediaElement { } } + pub fn get_ready_state(&self) -> ReadyState { + self.ready_state.get() + } + fn media_type_id(&self) -> HTMLMediaElementTypeId { match self.upcast::().type_id() { NodeTypeId::Element(ElementTypeId::HTMLElement( @@ -952,8 +957,35 @@ impl HTMLMediaElement { if !self.have_metadata.get() { // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list // => "Once enough of the media data has been fetched to determine the duration..." + // Step 1. + // servo-media owns the media timeline. + + // Step 2. + // XXX(ferjm) Update the timeline offset. + + // Step 3. + // XXX(ferjm) Set the current and official playback positions + // to the earliest possible position. + + // Step 4. + // XXX(ferjm) Update duration. + + // Step 5. + if self.is::() { + assert_ne!(self.ready_state.get(), ReadyState::HaveNothing); + let video_elem = self.downcast::().unwrap(); + video_elem.set_video_width(metadata.width); + video_elem.set_video_height(metadata.height); + let window = window_from_node(self); + window.dom_manipulation_task_source().queue_simple_event( + self.upcast(), + atom!("resize"), + &window, + ); + } + if let Some(_dur) = metadata.duration { - // Setp 6. + // Step 6. self.change_ready_state(ReadyState::HaveMetadata); self.have_metadata.set(true); } diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs index 8561aa051e1..5ce8d941b61 100644 --- a/components/script/dom/htmlvideoelement.rs +++ b/components/script/dom/htmlvideoelement.rs @@ -3,16 +3,20 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::Bindings::HTMLVideoElementBinding; +use dom::bindings::codegen::Bindings::HTMLVideoElementBinding::HTMLVideoElementMethods; use dom::bindings::root::DomRoot; use dom::document::Document; -use dom::htmlmediaelement::HTMLMediaElement; +use dom::htmlmediaelement::{HTMLMediaElement, ReadyState}; use dom::node::Node; use dom_struct::dom_struct; use html5ever::{LocalName, Prefix}; +use std::cell::Cell; #[dom_struct] pub struct HTMLVideoElement { htmlmediaelement: HTMLMediaElement, + video_width: Cell, + video_height: Cell, } impl HTMLVideoElement { @@ -23,6 +27,8 @@ impl HTMLVideoElement { ) -> HTMLVideoElement { HTMLVideoElement { htmlmediaelement: HTMLMediaElement::new_inherited(local_name, prefix, document), + video_width: Cell::new(0), + video_height: Cell::new(0), } } @@ -40,4 +46,28 @@ impl HTMLVideoElement { HTMLVideoElementBinding::Wrap, ) } + + pub fn set_video_width(&self, width: u32) { + self.video_width.set(width); + } + + pub fn set_video_height(&self, height: u32) { + self.video_height.set(height); + } +} + +impl HTMLVideoElementMethods for HTMLVideoElement { + fn VideoWidth(&self) -> u32 { + if self.htmlmediaelement.get_ready_state() == ReadyState::HaveNothing { + return 0; + } + self.video_width.get() + } + + fn VideoHeight(&self) -> u32 { + if self.htmlmediaelement.get_ready_state() == ReadyState::HaveNothing { + return 0; + } + self.video_height.get() + } } diff --git a/components/script/dom/webidls/HTMLVideoElement.webidl b/components/script/dom/webidls/HTMLVideoElement.webidl index bfd1be006ea..a3a34e7c47e 100644 --- a/components/script/dom/webidls/HTMLVideoElement.webidl +++ b/components/script/dom/webidls/HTMLVideoElement.webidl @@ -9,8 +9,8 @@ interface HTMLVideoElement : HTMLMediaElement { // attribute unsigned long width; // [CEReactions] // attribute unsigned long height; - // readonly attribute unsigned long videoWidth; - // readonly attribute unsigned long videoHeight; + readonly attribute unsigned long videoWidth; + readonly attribute unsigned long videoHeight; // [CEReactions] // attribute DOMString poster; }; From f4ba7e503bfa89805950e29cd9bd729e99264bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 21 Sep 2018 12:58:03 +0200 Subject: [PATCH 26/38] Media element duration param --- components/atoms/static_atoms.txt | 1 + components/script/dom/htmlmediaelement.rs | 35 ++++++++++++++----- components/script/dom/htmlvideoelement.rs | 2 ++ .../dom/webidls/HTMLMediaElement.webidl | 2 +- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt index 151ad41d914..4281c7004d0 100644 --- a/components/atoms/static_atoms.txt +++ b/components/atoms/static_atoms.txt @@ -18,6 +18,7 @@ cursive date datetime-local dir +durationchange email emptied ended diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 605b6cd8a99..4dd589d937e 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -49,6 +49,7 @@ use servo_media::ServoMedia; use servo_url::ServoUrl; use std::cell::Cell; use std::collections::VecDeque; +use std::f64; use std::mem; use std::rc::Rc; use std::sync::{Arc, Mutex}; @@ -165,6 +166,8 @@ pub struct HTMLMediaElement { fetch_canceller: DomRefCell, /// https://html.spec.whatwg.org/multipage/media.html#show-poster-flag show_poster: Cell, + /// https://html.spec.whatwg.org/multipage/media.html#dom-media-duration + duration: Cell, } /// @@ -211,6 +214,7 @@ impl HTMLMediaElement { Arc::new(Mutex::new(MediaFrameRenderer::new(document.window().get_webrender_api_sender()))), fetch_canceller: DomRefCell::new(Default::default()), show_poster: Cell::new(true), + duration: Cell::new(f64::NAN), } } @@ -838,7 +842,7 @@ impl HTMLMediaElement { // FIXME(nox): Set timeline offset to NaN. // Step 6.10. - // FIXME(nox): Set duration to NaN. + self.duration.set(f64::NAN); } // Step 7. @@ -968,7 +972,18 @@ impl HTMLMediaElement { // to the earliest possible position. // Step 4. - // XXX(ferjm) Update duration. + if let Some(duration) = metadata.duration { + self.duration.set(duration.as_secs() as f64); + } else { + self.duration.set(f64::INFINITY); + } + let window = window_from_node(self); + let task_source = window.dom_manipulation_task_source(); + task_source.queue_simple_event( + self.upcast(), + atom!("durationchange"), + &window, + ); // Step 5. if self.is::() { @@ -976,19 +991,16 @@ impl HTMLMediaElement { let video_elem = self.downcast::().unwrap(); video_elem.set_video_width(metadata.width); video_elem.set_video_height(metadata.height); - let window = window_from_node(self); - window.dom_manipulation_task_source().queue_simple_event( + task_source.queue_simple_event( self.upcast(), atom!("resize"), &window, ); } - if let Some(_dur) = metadata.duration { - // Step 6. - self.change_ready_state(ReadyState::HaveMetadata); - self.have_metadata.set(true); - } + // Step 6. + self.change_ready_state(ReadyState::HaveMetadata); + self.have_metadata.set(true); } else { // => set the element's delaying-the-load-event flag to false self.change_ready_state(ReadyState::HaveCurrentData); @@ -1104,6 +1116,11 @@ impl HTMLMediaElementMethods for HTMLMediaElement { fn Paused(&self) -> bool { self.paused.get() } + + // https://html.spec.whatwg.org/multipage/media.html#dom-media-duration + fn Duration(&self) -> f64 { + self.duration.get() + } } impl VirtualMethods for HTMLMediaElement { diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs index 5ce8d941b61..142887a855e 100644 --- a/components/script/dom/htmlvideoelement.rs +++ b/components/script/dom/htmlvideoelement.rs @@ -15,7 +15,9 @@ use std::cell::Cell; #[dom_struct] pub struct HTMLVideoElement { htmlmediaelement: HTMLMediaElement, + /// https://html.spec.whatwg.org/multipage/media.html#dom-video-videowidth video_width: Cell, + /// https://html.spec.whatwg.org/multipage/media.html#dom-video-videoheight video_height: Cell, } diff --git a/components/script/dom/webidls/HTMLMediaElement.webidl b/components/script/dom/webidls/HTMLMediaElement.webidl index b67a5e3c1fe..e00b1de7c4f 100644 --- a/components/script/dom/webidls/HTMLMediaElement.webidl +++ b/components/script/dom/webidls/HTMLMediaElement.webidl @@ -39,7 +39,7 @@ interface HTMLMediaElement : HTMLElement { // playback state // attribute double currentTime; // void fastSeek(double time); - // readonly attribute unrestricted double duration; + readonly attribute unrestricted double duration; // Date getStartDate(); readonly attribute boolean paused; // attribute double defaultPlaybackRate; From 50582f1548587ff66bdea4176a6a01f94c1e7e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 21 Sep 2018 14:10:59 +0200 Subject: [PATCH 27/38] Rustfmt and make tidy happy --- components/layout/fragment.rs | 2 +- components/script/dom/htmlmediaelement.rs | 70 ++++++++++++----------- components/script/dom/htmlvideoelement.rs | 6 +- components/script/dom/node.rs | 2 +- components/script_traits/lib.rs | 4 +- 5 files changed, 44 insertions(+), 40 deletions(-) diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index f79dcc8d3d0..33a6ac3dd3b 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -31,8 +31,8 @@ use msg::constellation_msg::{BrowsingContextId, PipelineId}; use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder}; use range::*; -use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource, HTMLMediaData, SVGSVGData}; +use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; use serde::ser::{Serialize, SerializeStruct, Serializer}; use servo_url::ServoUrl; use std::{f32, fmt}; diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 4dd589d937e..26c6242a083 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -43,9 +43,9 @@ use net_traits::request::{CredentialsMode, Destination, RequestInit}; use network_listener::{NetworkListener, PreInvoke}; use script_layout_interface::HTMLMediaData; use script_thread::ScriptThread; +use servo_media::ServoMedia; use servo_media::player::{PlaybackState, Player, PlayerEvent}; use servo_media::player::frame::{Frame, FrameRenderer}; -use servo_media::ServoMedia; use servo_url::ServoUrl; use std::cell::Cell; use std::collections::VecDeque; @@ -112,12 +112,12 @@ impl FrameRenderer for MediaFrameRenderer { *image_key = new_image_key; *width = frame.get_width(); *height = frame.get_height(); - } + }, None => { let image_key = self.api.generate_image_key(); txn.add_image(image_key, descriptor, image_data, None); self.current_frame = Some((image_key, frame.get_width(), frame.get_height())); - } + }, } self.api.update_resources(txn.resource_updates); @@ -164,9 +164,9 @@ pub struct HTMLMediaElement { #[ignore_malloc_size_of = "Arc"] frame_renderer: Arc>, fetch_canceller: DomRefCell, - /// https://html.spec.whatwg.org/multipage/media.html#show-poster-flag + /// https://html.spec.whatwg.org/multipage/#show-poster-flag show_poster: Cell, - /// https://html.spec.whatwg.org/multipage/media.html#dom-media-duration + /// https://html.spec.whatwg.org/multipage/#dom-media-duration duration: Cell, } @@ -210,8 +210,9 @@ impl HTMLMediaElement { in_flight_play_promises_queue: Default::default(), have_metadata: Cell::new(false), player: ServoMedia::get().unwrap().create_player().unwrap(), - frame_renderer: - Arc::new(Mutex::new(MediaFrameRenderer::new(document.window().get_webrender_api_sender()))), + frame_renderer: Arc::new(Mutex::new(MediaFrameRenderer::new( + document.window().get_webrender_api_sender(), + ))), fetch_canceller: DomRefCell::new(Default::default()), show_poster: Cell::new(true), duration: Cell::new(f64::NAN), @@ -321,7 +322,8 @@ impl HTMLMediaElement { }); }), window.upcast(), - ).unwrap(); + ) + .unwrap(); } // Step 8. @@ -331,7 +333,7 @@ impl HTMLMediaElement { // Not applicable here, the promise is returned from Play. } - /// https://html.spec.whatwg.org/multipage/media.html#time-marches-on + /// https://html.spec.whatwg.org/multipage/#time-marches-on fn time_marches_on(&self) { // TODO: implement this. } @@ -540,7 +542,7 @@ impl HTMLMediaElement { fn resource_selection_algorithm_sync(&self, base_url: ServoUrl) { // Step 5. // FIXME(ferjm): Implement blocked_on_parser logic - // https://html.spec.whatwg.org/multipage/media.html#blocked-on-parser + // https://html.spec.whatwg.org/multipage/#blocked-on-parser // FIXME(nox): Maybe populate the list of pending text tracks. // Step 6. @@ -670,7 +672,8 @@ impl HTMLMediaElement { this.root().delay_load_event(false); }), window.upcast(), - ).unwrap(); + ) + .unwrap(); // Steps 4.remote.1.4. // FIXME(nox): Somehow we should wait for the task from previous @@ -719,8 +722,13 @@ impl HTMLMediaElement { ); 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(); + global + .core_resource_thread() + .send(CoreResourceMsg::Fetch( + request, + FetchChannels::ResponseMsg(action_sender, Some(cancel_receiver)), + )) + .unwrap(); }, Resource::Object => { // FIXME(nox): Actually do something with the object. @@ -931,7 +939,8 @@ impl HTMLMediaElement { let (action_sender, action_receiver) = ipc::channel().unwrap(); self.player.register_event_handler(action_sender); - self.player.register_frame_renderer(self.frame_renderer.clone()); + self.player + .register_frame_renderer(self.frame_renderer.clone()); // XXXferjm this can fail. self.player.setup().unwrap(); @@ -950,7 +959,8 @@ impl HTMLMediaElement { this.root().handle_player_event(&event); }), &task_canceller, - ).unwrap(); + ) + .unwrap(); }), ); } @@ -979,11 +989,7 @@ impl HTMLMediaElement { } let window = window_from_node(self); let task_source = window.dom_manipulation_task_source(); - task_source.queue_simple_event( - self.upcast(), - atom!("durationchange"), - &window, - ); + task_source.queue_simple_event(self.upcast(), atom!("durationchange"), &window); // Step 5. if self.is::() { @@ -991,40 +997,38 @@ impl HTMLMediaElement { let video_elem = self.downcast::().unwrap(); video_elem.set_video_width(metadata.width); video_elem.set_video_height(metadata.height); - task_source.queue_simple_event( - self.upcast(), - atom!("resize"), - &window, - ); + task_source.queue_simple_event(self.upcast(), atom!("resize"), &window); } // Step 6. self.change_ready_state(ReadyState::HaveMetadata); self.have_metadata.set(true); + + // XXX(ferjm) Steps 7 to 13. } else { // => set the element's delaying-the-load-event flag to false self.change_ready_state(ReadyState::HaveCurrentData); } - } + }, PlayerEvent::StateChanged(ref state) => match *state { PlaybackState::Paused => { if self.ready_state.get() == ReadyState::HaveMetadata { self.change_ready_state(ReadyState::HaveEnoughData); } - } - _ => {} + }, + _ => {}, }, - PlayerEvent::EndOfStream => {} + PlayerEvent::EndOfStream => {}, PlayerEvent::FrameUpdated => { self.upcast::().dirty(NodeDamage::OtherNodeDamage); - } + }, PlayerEvent::Error => { self.error.set(Some(&*MediaError::new( &*window_from_node(self), MEDIA_ERR_DECODE, ))); self.upcast::().fire_event(atom!("error")); - } + }, } } } @@ -1117,7 +1121,7 @@ impl HTMLMediaElementMethods for HTMLMediaElement { self.paused.get() } - // https://html.spec.whatwg.org/multipage/media.html#dom-media-duration + // https://html.spec.whatwg.org/multipage/#dom-media-duration fn Duration(&self) -> f64 { self.duration.get() } @@ -1301,7 +1305,7 @@ impl FetchResponseListener for HTMLMediaElementContext { // Until then, we comment out the failure steps. // //elem.queue_dedicated_media_source_failure_steps(); - // => "Once the entire media resource has been fetched..." + // => "Once the entire media resource has been fetched..." } else if status.is_ok() { elem.change_ready_state(ReadyState::HaveEnoughData); diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs index 142887a855e..59c93bfea6e 100644 --- a/components/script/dom/htmlvideoelement.rs +++ b/components/script/dom/htmlvideoelement.rs @@ -15,9 +15,9 @@ use std::cell::Cell; #[dom_struct] pub struct HTMLVideoElement { htmlmediaelement: HTMLMediaElement, - /// https://html.spec.whatwg.org/multipage/media.html#dom-video-videowidth + /// https://html.spec.whatwg.org/multipage/#dom-video-videowidth video_width: Cell, - /// https://html.spec.whatwg.org/multipage/media.html#dom-video-videoheight + /// https://html.spec.whatwg.org/multipage/#dom-video-videoheight video_height: Cell, } @@ -59,6 +59,7 @@ impl HTMLVideoElement { } impl HTMLVideoElementMethods for HTMLVideoElement { + // https://html.spec.whatwg.org/multipage/#dom-video-videowidth fn VideoWidth(&self) -> u32 { if self.htmlmediaelement.get_ready_state() == ReadyState::HaveNothing { return 0; @@ -66,6 +67,7 @@ impl HTMLVideoElementMethods for HTMLVideoElement { self.video_width.get() } + // https://html.spec.whatwg.org/multipage/#dom-video-videoheight fn VideoHeight(&self) -> u32 { if self.htmlmediaelement.get_ready_state() == ReadyState::HaveNothing { return 0; diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 43fe454bc7f..7899e494341 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -63,9 +63,9 @@ use libc::{self, c_void, uintptr_t}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use msg::constellation_msg::{BrowsingContextId, PipelineId}; use ref_slice::ref_slice; -use script_layout_interface::message::Msg; use script_layout_interface::{HTMLCanvasData, HTMLMediaData, LayoutElementType, LayoutNodeType}; use script_layout_interface::{OpaqueStyleAndLayoutData, SVGSVGData, TrustedNodeAddress}; +use script_layout_interface::message::Msg; use script_thread::ScriptThread; use script_traits::DocumentActivity; use script_traits::UntrustedNodeAddress; diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 60b62f6b270..802e61ea172 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -72,9 +72,7 @@ use style_traits::CSSPixel; use style_traits::SpeculativePainter; use style_traits::cursor::CursorKind; use webdriver_msg::{LoadStatus, WebDriverScriptCommand}; -use webrender_api::{ - DevicePixel, DeviceUintSize, DocumentId, ExternalScrollId, ImageKey, RenderApiSender, -}; +use webrender_api::{DevicePixel, DeviceUintSize, DocumentId, ExternalScrollId, ImageKey, RenderApiSender}; use webvr_traits::{WebVREvent, WebVRMsg}; pub use script_msg::{LayoutMsg, ScriptMsg, EventResult, LogEntry}; From 5bbd09769c3d8910a11d014ed512a0e40f093c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 21 Sep 2018 16:32:59 +0200 Subject: [PATCH 28/38] Set input size --- components/script/dom/htmlmediaelement.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 26c6242a083..df29a860a3f 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -33,6 +33,7 @@ use dom::virtualmethods::VirtualMethods; use dom_struct::dom_struct; use fetch::FetchCanceller; use html5ever::{LocalName, Prefix}; +use hyper::header::ContentLength; use ipc_channel::ipc; use ipc_channel::router::ROUTER; use microtask::{Microtask, MicrotaskRunnable}; @@ -993,7 +994,6 @@ impl HTMLMediaElement { // Step 5. if self.is::() { - assert_ne!(self.ready_state.get(), ReadyState::HaveNothing); let video_elem = self.downcast::().unwrap(); video_elem.set_video_width(metadata.width); video_elem.set_video_height(metadata.height); @@ -1235,6 +1235,14 @@ impl FetchResponseListener for HTMLMediaElementContext { FetchMetadata::Filtered { unsafe_, .. } => unsafe_, }); + if let Some(metadata) = self.metadata.as_ref() { + if let Some(headers) = metadata.headers.as_ref() { + if let Some(content_length) = headers.get::() { + self.elem.root().player.set_input_size(**content_length); + } + } + } + let status_is_ok = self .metadata .as_ref() From dba61ad1df38edd4a0d6fd911d61bbe26295d167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 21 Sep 2018 17:49:13 +0200 Subject: [PATCH 29/38] Do not set metadata until we have enough data --- components/script/dom/htmlmediaelement.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index df29a860a3f..3a573fa0b81 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -969,7 +969,7 @@ impl HTMLMediaElement { fn handle_player_event(&self, event: &PlayerEvent) { match *event { PlayerEvent::MetadataUpdated(ref metadata) => { - if !self.have_metadata.get() { + if !self.have_metadata.get() && metadata.duration.is_some() { // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list // => "Once enough of the media data has been fetched to determine the duration..." // Step 1. From 1c92240310001ef110ea31498b7d0cfbd1365abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 25 Sep 2018 07:11:05 +0200 Subject: [PATCH 30/38] Fix HAVE_METADATA and HAVE_CURRENT_DATA state transitions --- components/script/dom/htmlmediaelement.rs | 75 +++++++++++++---------- etc/ci/buildbot_steps.yml | 1 + 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 3a573fa0b81..5096a174ab7 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -510,6 +510,7 @@ impl HTMLMediaElement { // https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm fn invoke_resource_selection_algorithm(&self) { + println!("invoke_resource_selection_algorithm"); // Step 1. self.network_state.set(NetworkState::NoSource); @@ -541,6 +542,7 @@ impl HTMLMediaElement { // https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm fn resource_selection_algorithm_sync(&self, base_url: ServoUrl) { + println!("resource_selection_algorithm_sync"); // Step 5. // FIXME(ferjm): Implement blocked_on_parser logic // https://html.spec.whatwg.org/multipage/#blocked-on-parser @@ -641,6 +643,7 @@ impl HTMLMediaElement { // https://html.spec.whatwg.org/multipage/#concept-media-load-resource fn resource_fetch_algorithm(&self, resource: Resource) { + println!("resource_fetch_algorithm"); // Steps 1-2. // Unapplicable, the `resource` variable already conveys which mode // is in use. @@ -706,7 +709,9 @@ impl HTMLMediaElement { ..RequestInit::default() }; + println!("Setting up media player"); self.setup_media_player(); + println!("Media player setup"); let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self))); let (action_sender, action_receiver) = ipc::channel().unwrap(); let window = window_from_node(self); @@ -790,6 +795,7 @@ impl HTMLMediaElement { // https://html.spec.whatwg.org/multipage/#media-element-load-algorithm fn media_element_load_algorithm(&self) { + println!("media_element_load_algorithm"); // Reset the flag that signals whether loadeddata was ever fired for // this invokation of the load algorithm. self.fired_loadeddata_event.set(false); @@ -969,46 +975,42 @@ impl HTMLMediaElement { fn handle_player_event(&self, event: &PlayerEvent) { match *event { PlayerEvent::MetadataUpdated(ref metadata) => { - if !self.have_metadata.get() && metadata.duration.is_some() { - // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list - // => "Once enough of the media data has been fetched to determine the duration..." - // Step 1. - // servo-media owns the media timeline. + println!("PlayerEvent::MetadataUpdated"); + // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list + // => "Once enough of the media data has been fetched to determine the duration..." + // Step 1. + // servo-media owns the media timeline. - // Step 2. - // XXX(ferjm) Update the timeline offset. + // Step 2. + // XXX(ferjm) Update the timeline offset. - // Step 3. - // XXX(ferjm) Set the current and official playback positions - // to the earliest possible position. + // Step 3. + // XXX(ferjm) Set the current and official playback positions + // to the earliest possible position. - // Step 4. - if let Some(duration) = metadata.duration { - self.duration.set(duration.as_secs() as f64); - } else { - self.duration.set(f64::INFINITY); - } - let window = window_from_node(self); - let task_source = window.dom_manipulation_task_source(); - task_source.queue_simple_event(self.upcast(), atom!("durationchange"), &window); + // Step 4. + if let Some(duration) = metadata.duration { + self.duration.set(duration.as_secs() as f64); + } else { + self.duration.set(f64::INFINITY); + } + let window = window_from_node(self); + let task_source = window.dom_manipulation_task_source(); + task_source.queue_simple_event(self.upcast(), atom!("durationchange"), &window); - // Step 5. - if self.is::() { - let video_elem = self.downcast::().unwrap(); - video_elem.set_video_width(metadata.width); - video_elem.set_video_height(metadata.height); - task_source.queue_simple_event(self.upcast(), atom!("resize"), &window); - } + // Step 5. + if self.is::() { + let video_elem = self.downcast::().unwrap(); + video_elem.set_video_width(metadata.width); + video_elem.set_video_height(metadata.height); + task_source.queue_simple_event(self.upcast(), atom!("resize"), &window); + } - // Step 6. - self.change_ready_state(ReadyState::HaveMetadata); - self.have_metadata.set(true); + // Step 6. + self.change_ready_state(ReadyState::HaveMetadata); + self.have_metadata.set(true); // XXX(ferjm) Steps 7 to 13. - } else { - // => set the element's delaying-the-load-event flag to false - self.change_ready_state(ReadyState::HaveCurrentData); - } }, PlayerEvent::StateChanged(ref state) => match *state { PlaybackState::Paused => { @@ -1274,6 +1276,13 @@ impl FetchResponseListener for HTMLMediaElementContext { return; } + // Make sure we don't skip the HaveMetadata state. + if elem.have_metadata.get() { + // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list + // => set the element's delaying-the-load-event flag to false + elem.change_ready_state(ReadyState::HaveCurrentData); + } + // https://html.spec.whatwg.org/multipage/#concept-media-load-resource step 4, // => "If mode is remote" step 2 if time::get_time() > self.next_progress_event { diff --git a/etc/ci/buildbot_steps.yml b/etc/ci/buildbot_steps.yml index 908b813875b..da27cb4db1f 100644 --- a/etc/ci/buildbot_steps.yml +++ b/etc/ci/buildbot_steps.yml @@ -3,6 +3,7 @@ env: RUSTFLAGS: -Dwarnings CARGO_INCREMENTAL: "0" SCCACHE_IDLE_TIMEOUT: "1200" + GST_DEBUG: '3' mac-rel-wpt1: - ./mach clean-nightlies --keep 3 --force From 59d8c95b23c85ec70eaf020bee97ce74584239ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Tue, 25 Sep 2018 18:57:30 +0200 Subject: [PATCH 31/38] Network EOF does't imply media processing EOS Since media processing is highly asynchronous, there is no need to match one event with the other. Then error handling is done when the player emits the EOS event. The have_metadata attribute is not required anymore. --- components/script/dom/htmlmediaelement.rs | 37 ++++++----------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 5096a174ab7..f19b6f56404 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -158,8 +158,6 @@ pub struct HTMLMediaElement { /// Play promises which are soon to be fulfilled by a queued task. #[ignore_malloc_size_of = "promises are hard"] in_flight_play_promises_queue: DomRefCell]>, ErrorResult)>>, - /// Whether the media metadata has been completely received. - have_metadata: Cell, #[ignore_malloc_size_of = "servo_media"] player: Box, #[ignore_malloc_size_of = "Arc"] @@ -209,7 +207,6 @@ impl HTMLMediaElement { delaying_the_load_event_flag: Default::default(), pending_play_promises: Default::default(), in_flight_play_promises_queue: Default::default(), - have_metadata: Cell::new(false), player: ServoMedia::get().unwrap().create_player().unwrap(), frame_renderer: Arc::new(Mutex::new(MediaFrameRenderer::new( document.window().get_webrender_api_sender(), @@ -1008,7 +1005,6 @@ impl HTMLMediaElement { // Step 6. self.change_ready_state(ReadyState::HaveMetadata); - self.have_metadata.set(true); // XXX(ferjm) Steps 7 to 13. }, @@ -1020,7 +1016,15 @@ impl HTMLMediaElement { }, _ => {}, }, - PlayerEvent::EndOfStream => {}, + PlayerEvent::EndOfStream => { + println!("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 + // 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(); + } + }, PlayerEvent::FrameUpdated => { self.upcast::().dirty(NodeDamage::OtherNodeDamage); }, @@ -1276,13 +1280,6 @@ impl FetchResponseListener for HTMLMediaElementContext { return; } - // Make sure we don't skip the HaveMetadata state. - if elem.have_metadata.get() { - // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list - // => set the element's delaying-the-load-event flag to false - elem.change_ready_state(ReadyState::HaveCurrentData); - } - // https://html.spec.whatwg.org/multipage/#concept-media-load-resource step 4, // => "If mode is remote" step 2 if time::get_time() > self.next_progress_event { @@ -1309,21 +1306,7 @@ impl FetchResponseListener for HTMLMediaElementContext { eprintln!("Couldn't signal EOS to player"); } - // => "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 !elem.have_metadata.get() { - // FIXME(victor): adjust player's max-size (or buffering). - // - // In short streams the EOS might arrive before extracting the stream - // metadata. This is because the internal queue in the GStreamer appsrc element, - // has a size of 200K and it pushes the data until it is reached. It would be nice - // to add a property to set the max-data in appsrc according to reported size of - // the stream. - // Until then, we comment out the failure steps. - // - //elem.queue_dedicated_media_source_failure_steps(); - // => "Once the entire media resource has been fetched..." - } else if status.is_ok() { + if status.is_ok() { elem.change_ready_state(ReadyState::HaveEnoughData); elem.upcast::().fire_event(atom!("progress")); From cc6ecab7a35dee425e1cd2b57d91baa64d76e148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 2 Oct 2018 11:09:41 +0200 Subject: [PATCH 32/38] Fix Travis complains about lock file --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f07221dd8a8..8c7da7e5584 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4545,8 +4545,8 @@ dependencies = [ "checksum serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "5c508584d9913df116b91505eec55610a2f5b16e9ed793c46e4d0152872b3e74" "checksum servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21069a884c33fe6ee596975e1f3849ed88c4ec857fbaf11d33672d8ebe051217" "checksum servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93f799b649b4a2bf362398910eca35240704c7e765e780349b2bb1070d892262" -"checksum servo-fontconfig-sys 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa080856db55f188aaf36f01cae8c03448a6056552adb77d461179e44e1a14" -"checksum servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9232032c2e85118c0282c6562c84cab12316e655491ba0a5d1905b2320060d1b" +"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)" = "" From e31339245c9d7bf31870b1ce0be5c9bb90e60d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 2 Oct 2018 12:24:32 +0200 Subject: [PATCH 33/38] Move player setup to common path, deal with setup error and clean debug msgs --- components/script/dom/htmlmediaelement.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index f19b6f56404..642c71d4b4a 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -507,7 +507,6 @@ impl HTMLMediaElement { // https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm fn invoke_resource_selection_algorithm(&self) { - println!("invoke_resource_selection_algorithm"); // Step 1. self.network_state.set(NetworkState::NoSource); @@ -539,7 +538,6 @@ impl HTMLMediaElement { // https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm fn resource_selection_algorithm_sync(&self, base_url: ServoUrl) { - println!("resource_selection_algorithm_sync"); // Step 5. // FIXME(ferjm): Implement blocked_on_parser logic // https://html.spec.whatwg.org/multipage/#blocked-on-parser @@ -640,7 +638,10 @@ impl HTMLMediaElement { // https://html.spec.whatwg.org/multipage/#concept-media-load-resource fn resource_fetch_algorithm(&self, resource: Resource) { - println!("resource_fetch_algorithm"); + if self.setup_media_player().is_err() { + self.queue_dedicated_media_source_failure_steps(); + return; + } // Steps 1-2. // Unapplicable, the `resource` variable already conveys which mode // is in use. @@ -706,9 +707,6 @@ impl HTMLMediaElement { ..RequestInit::default() }; - println!("Setting up media player"); - self.setup_media_player(); - println!("Media player setup"); let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self))); let (action_sender, action_receiver) = ipc::channel().unwrap(); let window = window_from_node(self); @@ -792,7 +790,6 @@ impl HTMLMediaElement { // https://html.spec.whatwg.org/multipage/#media-element-load-algorithm fn media_element_load_algorithm(&self) { - println!("media_element_load_algorithm"); // Reset the flag that signals whether loadeddata was ever fired for // this invokation of the load algorithm. self.fired_loadeddata_event.set(false); @@ -939,14 +936,15 @@ impl HTMLMediaElement { } // servo media player - fn setup_media_player(&self) { + fn setup_media_player(&self) -> Result<(), ()>{ let (action_sender, action_receiver) = ipc::channel().unwrap(); self.player.register_event_handler(action_sender); self.player .register_frame_renderer(self.frame_renderer.clone()); - // XXXferjm this can fail. - self.player.setup().unwrap(); + if self.player.setup().is_err() { + return Err(()); + } let trusted_node = Trusted::new(self); let window = window_from_node(self); @@ -967,12 +965,13 @@ impl HTMLMediaElement { .unwrap(); }), ); + + Ok(()) } fn handle_player_event(&self, event: &PlayerEvent) { match *event { PlayerEvent::MetadataUpdated(ref metadata) => { - println!("PlayerEvent::MetadataUpdated"); // https://html.spec.whatwg.org/multipage/#media-data-processing-steps-list // => "Once enough of the media data has been fetched to determine the duration..." // Step 1. @@ -1017,7 +1016,6 @@ impl HTMLMediaElement { _ => {}, }, PlayerEvent::EndOfStream => { - println!("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 // an unsupported format, or can otherwise not be rendered at all" From 0db628028a447d09170a185f713f91900fb1ddca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 2 Oct 2018 16:04:55 +0200 Subject: [PATCH 34/38] Update servo-media: handle decoder errors and use safer/nicer player API --- Cargo.lock | 11 ++++++----- components/script/dom/baseaudiocontext.rs | 5 +++-- components/script/dom/htmlmediaelement.rs | 5 +---- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c7da7e5584..b48002f9fcb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3224,7 +3224,7 @@ dependencies = [ [[package]] name = "servo-media" version = "0.1.0" -source = "git+https://github.com/servo/media#e700a0834c3f38d49890d846591fd699e7405a48" +source = "git+https://github.com/servo/media#d1524d451cb0493f40000daf4f2a58f59b535ffa" 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)", @@ -3234,11 +3234,12 @@ dependencies = [ [[package]] name = "servo-media-audio" version = "0.1.0" -source = "git+https://github.com/servo/media#e700a0834c3f38d49890d846591fd699e7405a48" +source = "git+https://github.com/servo/media#d1524d451cb0493f40000daf4f2a58f59b535ffa" dependencies = [ "boxfnonce 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "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)", @@ -3250,7 +3251,7 @@ dependencies = [ [[package]] name = "servo-media-gstreamer" version = "0.1.0" -source = "git+https://github.com/servo/media#e700a0834c3f38d49890d846591fd699e7405a48" +source = "git+https://github.com/servo/media#d1524d451cb0493f40000daf4f2a58f59b535ffa" dependencies = [ "byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3268,7 +3269,7 @@ dependencies = [ [[package]] name = "servo-media-player" version = "0.1.0" -source = "git+https://github.com/servo/media#e700a0834c3f38d49890d846591fd699e7405a48" +source = "git+https://github.com/servo/media#d1524d451cb0493f40000daf4f2a58f59b535ffa" dependencies = [ "ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3364,7 +3365,7 @@ dependencies = [ [[package]] name = "servo_media_derive" version = "0.1.0" -source = "git+https://github.com/servo/media#e700a0834c3f38d49890d846591fd699e7405a48" +source = "git+https://github.com/servo/media#d1524d451cb0493f40000daf4f2a58f59b535ffa" dependencies = [ "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/script/dom/baseaudiocontext.rs b/components/script/dom/baseaudiocontext.rs index b892049a8ec..0cb60a2fd80 100644 --- a/components/script/dom/baseaudiocontext.rs +++ b/components/script/dom/baseaudiocontext.rs @@ -461,7 +461,7 @@ impl BaseAudioContextMethods for BaseAudioContext { }), &canceller, ); - }).error(move || { + }).error(move |error| { let _ = task_source_.queue_with_canceller( task!(audio_decode_eos: move || { let this = this_.root(); @@ -473,7 +473,8 @@ impl BaseAudioContextMethods for BaseAudioContext { &DOMException::new(&this.global(), DOMErrorName::DataCloneError), ExceptionHandling::Report); } - resolver.promise.reject_error(Error::Type("Audio decode error".to_owned())); + let error = format!("Audio decode error {:?}", error); + resolver.promise.reject_error(Error::Type(error)); }), &canceller_, ); diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 642c71d4b4a..5fea53fad40 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -207,7 +207,7 @@ impl HTMLMediaElement { delaying_the_load_event_flag: Default::default(), pending_play_promises: Default::default(), in_flight_play_promises_queue: Default::default(), - player: ServoMedia::get().unwrap().create_player().unwrap(), + player: ServoMedia::get().unwrap().create_player(), frame_renderer: Arc::new(Mutex::new(MediaFrameRenderer::new( document.window().get_webrender_api_sender(), ))), @@ -942,9 +942,6 @@ impl HTMLMediaElement { self.player.register_event_handler(action_sender); self.player .register_frame_renderer(self.frame_renderer.clone()); - if self.player.setup().is_err() { - return Err(()); - } let trusted_node = Trusted::new(self); let window = window_from_node(self); From 6b0acc9cd891289d63a638bb53b233560309396b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 3 Oct 2018 14:01:58 +0200 Subject: [PATCH 35/38] Handle Player errors --- Cargo.lock | 10 +++--- components/script/dom/bindings/trace.rs | 3 +- components/script/dom/htmlmediaelement.rs | 40 +++++++++++++++-------- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b48002f9fcb..11dbb0af8e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3224,7 +3224,7 @@ dependencies = [ [[package]] name = "servo-media" version = "0.1.0" -source = "git+https://github.com/servo/media#d1524d451cb0493f40000daf4f2a58f59b535ffa" +source = "git+https://github.com/servo/media#ce50f1332cc2b70e859b793425c9ec7086137303" 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)", @@ -3234,7 +3234,7 @@ dependencies = [ [[package]] name = "servo-media-audio" version = "0.1.0" -source = "git+https://github.com/servo/media#d1524d451cb0493f40000daf4f2a58f59b535ffa" +source = "git+https://github.com/servo/media#ce50f1332cc2b70e859b793425c9ec7086137303" dependencies = [ "boxfnonce 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3251,7 +3251,7 @@ dependencies = [ [[package]] name = "servo-media-gstreamer" version = "0.1.0" -source = "git+https://github.com/servo/media#d1524d451cb0493f40000daf4f2a58f59b535ffa" +source = "git+https://github.com/servo/media#ce50f1332cc2b70e859b793425c9ec7086137303" dependencies = [ "byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3269,7 +3269,7 @@ dependencies = [ [[package]] name = "servo-media-player" version = "0.1.0" -source = "git+https://github.com/servo/media#d1524d451cb0493f40000daf4f2a58f59b535ffa" +source = "git+https://github.com/servo/media#ce50f1332cc2b70e859b793425c9ec7086137303" dependencies = [ "ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3365,7 +3365,7 @@ dependencies = [ [[package]] name = "servo_media_derive" version = "0.1.0" -source = "git+https://github.com/servo/media#d1524d451cb0493f40000daf4f2a58f59b535ffa" +source = "git+https://github.com/servo/media#ce50f1332cc2b70e859b793425c9ec7086137303" dependencies = [ "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index a625de741ab..8e720f28e25 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -91,6 +91,7 @@ use servo_arc::Arc as ServoArc; use servo_atoms::Atom; use servo_channel::{Receiver, Sender}; use servo_media::Backend; +use servo_media::Error as ServoMediaError; use servo_media::audio::analyser_node::AnalysisEngine; use servo_media::audio::buffer_source_node::AudioBuffer; use servo_media::audio::context::AudioContext; @@ -456,7 +457,7 @@ unsafe_no_jsmanaged_fields!(AudioBuffer); unsafe_no_jsmanaged_fields!(AudioContext); unsafe_no_jsmanaged_fields!(NodeId); unsafe_no_jsmanaged_fields!(AnalysisEngine, DistanceModel, PanningModel, ParamType); -unsafe_no_jsmanaged_fields!(Player); +unsafe_no_jsmanaged_fields!(Player); unsafe_no_jsmanaged_fields!(Mutex); unsafe_no_jsmanaged_fields!(RenderApiSender); diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 5fea53fad40..97d94995f95 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -44,6 +44,7 @@ use net_traits::request::{CredentialsMode, Destination, RequestInit}; use network_listener::{NetworkListener, PreInvoke}; 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::frame::{Frame, FrameRenderer}; @@ -159,7 +160,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, @@ -316,7 +317,9 @@ impl HTMLMediaElement { } this.fulfill_in_flight_play_promises(|| { - this.player.play(); + if let Err(e) = this.player.play() { + eprintln!("Could not play media {:?}", e); + } }); }), window.upcast(), @@ -369,7 +372,9 @@ impl HTMLMediaElement { // Step 2.3.2. this.upcast::().fire_event(atom!("pause")); - this.player.pause(); + if let Err(e) = this.player.pause() { + eprintln!("Could not pause player {:?}", e); + } // Step 2.3.3. // Done after running this closure in @@ -406,7 +411,9 @@ impl HTMLMediaElement { this.fulfill_in_flight_play_promises(|| { // Step 2.1. this.upcast::().fire_event(atom!("playing")); - this.player.play(); + if let Err(e) = this.player.play() { + eprintln!("Could not play media {:?}", e); + } // Step 2.2. // Done after running this closure in @@ -638,7 +645,8 @@ impl HTMLMediaElement { // https://html.spec.whatwg.org/multipage/#concept-media-load-resource fn resource_fetch_algorithm(&self, resource: Resource) { - if self.setup_media_player().is_err() { + if let Err(e) = self.setup_media_player() { + eprintln!("Setup media player error {:?}", e); self.queue_dedicated_media_source_failure_steps(); return; } @@ -774,7 +782,9 @@ impl HTMLMediaElement { // Step 5. this.upcast::().fire_event(atom!("error")); - this.player.stop(); + if let Err(e) = this.player.stop() { + eprintln!("Could not stop player {:?}", e); + } // Step 6. // Done after running this closure in @@ -936,12 +946,12 @@ impl HTMLMediaElement { } // servo media player - fn setup_media_player(&self) -> Result<(), ()>{ + fn setup_media_player(&self) -> Result<(), ServoMediaError>{ let (action_sender, action_receiver) = ipc::channel().unwrap(); - self.player.register_event_handler(action_sender); + self.player.register_event_handler(action_sender)?; self.player - .register_frame_renderer(self.frame_renderer.clone()); + .register_frame_renderer(self.frame_renderer.clone())?; let trusted_node = Trusted::new(self); let window = window_from_node(self); @@ -1239,7 +1249,9 @@ impl FetchResponseListener for HTMLMediaElementContext { if let Some(metadata) = self.metadata.as_ref() { if let Some(headers) = metadata.headers.as_ref() { if let Some(content_length) = headers.get::() { - self.elem.root().player.set_input_size(**content_length); + if let Err(e) = self.elem.root().player.set_input_size(**content_length) { + eprintln!("Could not set player input size {:?}", e); + } } } } @@ -1270,8 +1282,8 @@ impl FetchResponseListener for HTMLMediaElementContext { let elem = self.elem.root(); // Push input data into the player. - if let Err(_) = elem.player.push_data(payload) { - eprintln!("Couldn't push input data to player"); + if let Err(e) = elem.player.push_data(payload) { + eprintln!("Could not push input data to player {:?}", e); return; } @@ -1297,8 +1309,8 @@ impl FetchResponseListener for HTMLMediaElementContext { let elem = self.elem.root(); // Signal the eos to player. - if let Err(_) = elem.player.end_of_stream() { - eprintln!("Couldn't signal EOS to player"); + if let Err(e) = elem.player.end_of_stream() { + eprintln!("Could not signal EOS to player {:?}", e); } if status.is_ok() { From 11ac049d278cb4eff6866943b81a0a3f4c28f108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 3 Oct 2018 20:39:19 +0200 Subject: [PATCH 36/38] Make sure we do not skip the HaveMetadata state. Fixes a bunch of tests --- components/script/dom/htmlmediaelement.rs | 5 +++++ .../load-events-networkState.html.ini | 4 ++++ .../resource-selection-invoke-insert-into-iframe.html.ini | 4 ++++ .../resource-selection-invoke-pause-networkState.html.ini | 4 ++++ ...lection-invoke-remove-from-document-networkState.html.ini | 4 ++++ 5 files changed, 21 insertions(+) create mode 100644 tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/load-events-networkState.html.ini create mode 100644 tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-insert-into-iframe.html.ini create mode 100644 tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-pause-networkState.html.ini create mode 100644 tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-remove-from-document-networkState.html.ini diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 97d94995f95..84380c8d11f 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -1314,6 +1314,11 @@ impl FetchResponseListener for HTMLMediaElementContext { } if status.is_ok() { + if elem.ready_state.get() == ReadyState::HaveNothing { + // Make sure that we don't skip the HaveMetadata and HaveCurrentData + // states for short streams. + elem.change_ready_state(ReadyState::HaveMetadata); + } elem.change_ready_state(ReadyState::HaveEnoughData); elem.upcast::().fire_event(atom!("progress")); diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/load-events-networkState.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/load-events-networkState.html.ini new file mode 100644 index 00000000000..95be7126728 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/load-events-networkState.html.ini @@ -0,0 +1,4 @@ +[load-events-networkState.html] + [NETWORK_NO_SOURCE] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-insert-into-iframe.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-insert-into-iframe.html.ini new file mode 100644 index 00000000000..dd5f01686e9 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-insert-into-iframe.html.ini @@ -0,0 +1,4 @@ +[resource-selection-invoke-insert-into-iframe.html] + [NOT invoking resource selection by inserting into other document with src set] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-pause-networkState.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-pause-networkState.html.ini new file mode 100644 index 00000000000..80becaced04 --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-pause-networkState.html.ini @@ -0,0 +1,4 @@ +[resource-selection-invoke-pause-networkState.html] + [NOT invoking resource selection with pause() when networkState is not NETWORK_EMPTY] + expected: FAIL + diff --git a/tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-remove-from-document-networkState.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-remove-from-document-networkState.html.ini new file mode 100644 index 00000000000..cbd728cd5fd --- /dev/null +++ b/tests/wpt/metadata/html/semantics/embedded-content/media-elements/loading-the-media-resource/resource-selection-invoke-remove-from-document-networkState.html.ini @@ -0,0 +1,4 @@ +[resource-selection-invoke-remove-from-document-networkState.html] + [NOT invoking resource selection with implicit pause() when networkState is not NETWORK_EMPTY] + expected: FAIL + From 92a10e2616c53a688b389098928af81f03173ea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 3 Oct 2018 22:23:45 +0200 Subject: [PATCH 37/38] Update tests expectations --- .../getter.html.ini | 21 ++++++++----------- .../html/dom/interfaces.https.html.ini | 21 ------------------- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/tests/wpt/metadata/html/dom/elements/the-innertext-idl-attribute/getter.html.ini b/tests/wpt/metadata/html/dom/elements/the-innertext-idl-attribute/getter.html.ini index ba5ca706e12..b87d4cead69 100644 --- a/tests/wpt/metadata/html/dom/elements/the-innertext-idl-attribute/getter.html.ini +++ b/tests/wpt/metadata/html/dom/elements/the-innertext-idl-attribute/getter.html.ini @@ -53,15 +53,9 @@ [opacity:0 child rendered ("
123abc")] expected: FAIL - [