Permalink
Browse files

Auto merge of #22399 - ferjm:poster.frame, r=jdm

Implement HTMLMediaElement poster attribute

- [X] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #22288
- [x] There are tests for these changes

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/22399)
<!-- Reviewable:end -->
  • Loading branch information...
bors-servo committed Jan 11, 2019
2 parents b49e751 + 8a8ee77 commit 33418c762759198745a21c1e948fbd5b4f915e99
@@ -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();
},
_ => (),
};
Oops, something went wrong.

0 comments on commit 33418c7

Please sign in to comment.