Barebones media UI

This commit is contained in:
Fernando Jiménez Moreno 2019-04-05 10:50:01 +02:00
parent 4f6b86f9f5
commit 1c02fc94a8
11 changed files with 177 additions and 25 deletions

View file

@ -15,6 +15,7 @@ use crate::dom::bindings::codegen::Bindings::HTMLMediaElementBinding::HTMLMediaE
use crate::dom::bindings::codegen::Bindings::HTMLSourceElementBinding::HTMLSourceElementMethods;
use crate::dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorConstants::*;
use crate::dom::bindings::codegen::Bindings::MediaErrorBinding::MediaErrorMethods;
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::NodeMethods;
use crate::dom::bindings::codegen::Bindings::TextTrackBinding::{TextTrackKind, TextTrackMode};
use crate::dom::bindings::codegen::InheritTypes::{ElementTypeId, HTMLElementTypeId};
use crate::dom::bindings::codegen::InheritTypes::{HTMLMediaElementTypeId, NodeTypeId};
@ -33,11 +34,12 @@ use crate::dom::document::Document;
use crate::dom::element::{
cors_setting_for_element, reflect_cross_origin_attribute, set_cross_origin_attribute,
};
use crate::dom::element::{AttributeMutation, Element};
use crate::dom::element::{AttributeMutation, Element, ElementCreator};
use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlelement::HTMLElement;
use crate::dom::htmlscriptelement::HTMLScriptElement;
use crate::dom::htmlsourceelement::HTMLSourceElement;
use crate::dom::htmlvideoelement::HTMLVideoElement;
use crate::dom::mediaerror::MediaError;
@ -45,6 +47,7 @@ use crate::dom::mediastream::MediaStream;
use crate::dom::node::{document_from_node, window_from_node, Node, NodeDamage, UnbindContext};
use crate::dom::performanceresourcetiming::InitiatorType;
use crate::dom::promise::Promise;
use crate::dom::shadowroot::IsUserAgentWidget;
use crate::dom::texttrack::TextTrack;
use crate::dom::texttracklist::TextTrackList;
use crate::dom::timeranges::{TimeRanges, TimeRangesContainer};
@ -59,6 +62,7 @@ use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingLi
use crate::script_thread::ScriptThread;
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use embedder_traits::resources::{self, Resource as EmbedderResource};
use euclid::Size2D;
use headers::{ContentLength, ContentRange, HeaderMapExt};
use html5ever::{LocalName, Prefix};
@ -335,6 +339,11 @@ pub struct HTMLMediaElement {
current_fetch_context: DomRefCell<Option<HTMLMediaElementFetchContext>>,
/// Player Id reported the player thread
id: Cell<u64>,
/// Media controls id.
/// In order to workaround the lack of privileged JS context, we secure the
/// the access to the "privileged" document.servoGetMediaControls(id) API by
/// keeping a whitelist of media controls identifiers.
media_controls_id: DomRefCell<Option<String>>,
}
/// <https://html.spec.whatwg.org/multipage/#dom-media-networkstate>
@ -397,6 +406,7 @@ impl HTMLMediaElement {
next_timeupdate_event: Cell::new(time::get_time() + Duration::milliseconds(250)),
current_fetch_context: DomRefCell::new(None),
id: Cell::new(0),
media_controls_id: DomRefCell::new(None),
}
}
@ -1712,6 +1722,47 @@ impl HTMLMediaElement {
.start(0)
.unwrap_or_else(|_| self.playback_position.get())
}
fn render_controls(&self) {
println!("render_controls");
// XXX cannot render controls while parsing.
// XXX render controls as a top layer.
// XXX check that controls are not already rendered.
let element = self.htmlelement.upcast::<Element>();
if let Ok(shadow_root) = element.attach_shadow(IsUserAgentWidget::Yes) {
let document = document_from_node(self);
let script = HTMLScriptElement::new(
local_name!("script"),
None,
&document,
ElementCreator::ScriptCreated,
);
let mut media_controls = resources::read_string(EmbedderResource::MediaControls);
// This is our hacky way to temporarily workaround the lack of a privileged
// JS context.
// The media controls UI accesses the document.servoGetMediaControls(id) API
// to get an instance to the media controls ShadowRoot.
// `id` needs to match the internally generated UUID assigned to a media element.
let id = document.register_media_controls(&shadow_root);
let media_controls = media_controls.as_mut_str().replace("@@@id@@@", &id);
*self.media_controls_id.borrow_mut() = Some(id);
script
.upcast::<Node>()
.SetTextContent(Some(DOMString::from(media_controls)));
if let Err(e) = shadow_root
.upcast::<Node>()
.AppendChild(&*script.upcast::<Node>())
{
warn!("Could not render media controls {:?}", e);
}
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
}
}
fn hide_controls(&self) {
println!("hide_controls");
}
}
// XXX Placeholder for [https://github.com/servo/servo/issues/22293]
@ -1754,6 +1805,9 @@ impl Drop for HTMLMediaElement {
.unwrap()
.shutdown_player(&client_context_id, player.clone());
}
if let Some(ref id) = *self.media_controls_id.borrow() {
document_from_node(self).unregister_media_controls(id);
}
}
}
@ -2177,19 +2231,23 @@ impl VirtualMethods for HTMLMediaElement {
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
self.super_type().unwrap().attribute_mutated(attr, mutation);
if &local_name!("muted") == attr.local_name() {
self.SetMuted(mutation.new_value(attr).is_some());
return;
}
if mutation.new_value(attr).is_none() {
return;
}
match attr.local_name() {
&local_name!("muted") => {
self.SetMuted(mutation.new_value(attr).is_some());
},
&local_name!("src") => {
if mutation.new_value(attr).is_none() {
return;
}
self.media_element_load_algorithm();
},
&local_name!("controls") => {
if mutation.new_value(attr).is_some() {
self.render_controls();
} else {
self.hide_controls();
}
},
_ => (),
};
}