Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement HTMLMediaElement poster attribute #22399

Merged
merged 6 commits into from Jan 15, 2019
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -64,6 +64,7 @@ pause
play
playing
popstate
postershown
print
progress
radio
@@ -38,13 +38,13 @@ use crate::dom::progressevent::ProgressEvent;
use crate::dom::values::UNSIGNED_LONG_MAX;
use crate::dom::virtualmethods::VirtualMethods;
use crate::dom::window::Window;
use crate::image_listener::{add_cache_listener_for_element, ImageCacheListener};
use crate::microtask::{Microtask, MicrotaskRunnable};
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use crate::script_thread::ScriptThread;
use crate::task_source::TaskSource;
use app_units::{Au, AU_PER_PX};
use cssparser::{Parser, ParserInput};

use dom_struct::dom_struct;
use euclid::Point2D;
use html5ever::{LocalName, Prefix};
@@ -167,7 +167,7 @@ struct ImageContext {
/// The cache ID for this request.
id: PendingImageId,
/// Used to mark abort
aborted: Cell<bool>,
aborted: bool,
/// The document associated with this request
doc: Trusted<Document>,
/// timing data for this resource
@@ -193,7 +193,7 @@ impl FetchResponseListener for ImageContext {
if let Some(ref content_type) = metadata.content_type {
let mime: Mime = content_type.clone().into_inner().into();
if mime.type_() == mime::MULTIPART && mime.subtype().as_str() == "x-mixed-replace" {
self.aborted.set(true);
self.aborted = true;
}
}
}
@@ -255,51 +255,13 @@ impl ResourceTimingListener for ImageContext {

impl PreInvoke for ImageContext {
fn should_invoke(&self) -> bool {
!self.aborted.get()
!self.aborted
}
}

impl HTMLImageElement {
/// Update the current image with a valid URL.
fn fetch_image(&self, img_url: &ServoUrl) {
fn add_cache_listener_for_element(
image_cache: Arc<dyn ImageCache>,
id: PendingImageId,
elem: &HTMLImageElement,
) {
let trusted_node = Trusted::new(elem);
let (responder_sender, responder_receiver) = ipc::channel().unwrap();

let window = window_from_node(elem);
let (task_source, canceller) = window
.task_manager()
.networking_task_source_with_canceller();
let generation = elem.generation.get();
ROUTER.add_route(
responder_receiver.to_opaque(),
Box::new(move |message| {
debug!("Got image {:?}", message);
// Return the image via a message to the script thread, which marks
// the element as dirty and triggers a reflow.
let element = trusted_node.clone();
let image = message.to().unwrap();
// FIXME(nox): Why are errors silenced here?
let _ = task_source.queue_with_canceller(
task!(process_image_response: move || {
let element = element.root();
// Ignore any image response for a previous request that has been discarded.
if generation == element.generation.get() {
element.process_image_response(image);
}
}),
&canceller,
);
}),
);

image_cache.add_listener(id, ImageResponder::new(responder_sender, id));
}

let window = window_from_node(self);
let image_cache = window.image_cache();
let response = image_cache.find_image_or_metadata(
@@ -317,7 +279,7 @@ impl HTMLImageElement {
},

Err(ImageState::Pending(id)) => {
add_cache_listener_for_element(image_cache.clone(), id, self);
add_cache_listener_for_element(image_cache, id, self);
},

Err(ImageState::LoadError) => {
@@ -339,7 +301,7 @@ impl HTMLImageElement {
image_cache: window.image_cache(),
status: Ok(()),
id: id,
aborted: Cell::new(false),
aborted: false,
doc: Trusted::new(&document),
resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource),
url: img_url.clone(),
@@ -1735,6 +1697,16 @@ impl FormControl for HTMLImageElement {
}
}

impl ImageCacheListener for HTMLImageElement {
fn generation_id(&self) -> u32 {
self.generation.get()
}

fn process_image_response(&self, response: ImageResponse) {
self.process_image_response(response);
}
}

fn image_dimension_setter(element: &Element, attr: LocalName, value: u32) {
// This setter is a bit weird: the IDL type is unsigned long, but it's parsed as
// a dimension for rendering.
@@ -51,10 +51,13 @@ use http::header::{self, HeaderMap, HeaderValue};
use ipc_channel::ipc;
use ipc_channel::router::ROUTER;
use mime::{self, Mime};
use net_traits::image::base::Image;
use net_traits::image_cache::ImageResponse;
use net_traits::request::{CredentialsMode, Destination, RequestInit};
use net_traits::{CoreResourceMsg, FetchChannels, FetchMetadata, FetchResponseListener, Metadata};
use net_traits::{NetworkError, ResourceFetchTiming, ResourceTimingType};
use script_layout_interface::HTMLMediaData;
use servo_config::prefs::PREFS;
use servo_media::player::frame::{Frame, FrameRenderer};
use servo_media::player::{PlaybackState, Player, PlayerError, PlayerEvent, StreamType};
use servo_media::ServoMedia;
@@ -85,6 +88,12 @@ impl MediaFrameRenderer {
very_old_frame: None,
}
}

fn render_poster_frame(&mut self, image: Arc<Image>) {
if let Some(image_id) = image.id {
self.current_frame = Some((image_id, image.width as i32, image.height as i32));
}
}
}

impl FrameRenderer for MediaFrameRenderer {
@@ -135,14 +144,11 @@ impl FrameRenderer for MediaFrameRenderer {
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
// media element event task source.
pub struct HTMLMediaElement {
htmlelement: HTMLElement,
/// <https://html.spec.whatwg.org/multipage/#dom-media-networkstate>
@@ -293,7 +299,7 @@ impl HTMLMediaElement {
/// we pass true to that method again.
///
/// <https://html.spec.whatwg.org/multipage/#delaying-the-load-event-flag>
fn delay_load_event(&self, delay: bool) {
pub fn delay_load_event(&self, delay: bool) {
let mut blocker = self.delaying_the_load_event_flag.borrow_mut();
if delay && blocker.is_none() {
*blocker = Some(LoadBlocker::new(&document_from_node(self), LoadType::Media));
@@ -1080,6 +1086,30 @@ impl HTMLMediaElement {
task_source.queue_simple_event(self.upcast(), atom!("seeked"), &window);
}

/// https://html.spec.whatwg.org/multipage/#poster-frame
pub fn process_poster_response(&self, image: ImageResponse) {
if !self.show_poster.get() {
return;
}

// Step 6.
if let ImageResponse::Loaded(image, _) = image {
self.frame_renderer
.lock()
.unwrap()
.render_poster_frame(image);
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
if let Some(testing_on) = PREFS.get("media.testing.enabled").as_boolean() {
if !testing_on {
return;
}
let window = window_from_node(self);
let task_source = window.task_manager().media_element_task_source();
task_source.queue_simple_event(self.upcast(), atom!("postershown"), &window);
}
}
}

fn setup_media_player(&self) -> Result<(), PlayerError> {
let (action_sender, action_receiver) = ipc::channel().unwrap();

@@ -1590,11 +1620,13 @@ impl VirtualMethods for HTMLMediaElement {
fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
self.super_type().unwrap().attribute_mutated(attr, mutation);

if mutation.new_value(attr).is_none() {
return;
}

match attr.local_name() {
&local_name!("src") => {
if mutation.new_value(attr).is_some() {
self.media_element_load_algorithm();
}
self.media_element_load_algorithm();
},
_ => (),
};
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.