Implement play, pause, paused, and autoplay APIs.

This commit is contained in:
Josh Matthews 2015-11-07 01:19:41 -05:00
parent 5960fbe604
commit e3db11fd8b
20 changed files with 118 additions and 399 deletions

View file

@ -162,6 +162,8 @@ pub struct HTMLMediaElement {
generation_id: Cell<u32>,
first_data_load: Cell<bool>,
error: MutNullableHeap<JS<MediaError>>,
paused: Cell<bool>,
autoplaying: Cell<bool>,
}
impl HTMLMediaElement {
@ -177,6 +179,8 @@ impl HTMLMediaElement {
generation_id: Cell::new(0),
first_data_load: Cell::new(true),
error: Default::default(),
paused: Cell::new(true),
autoplaying: Cell::new(true),
}
}
@ -185,6 +189,28 @@ impl HTMLMediaElement {
&self.htmlelement
}
// https://html.spec.whatwg.org/multipage/#playing-the-media-resource:internal-pause-steps
fn internal_pause_steps(&self) {
// Step 1
self.autoplaying.set(false);
// Step 2
if !self.Paused() {
// 2.1
self.paused.set(true);
// 2.2
self.queue_fire_simple_event("timeupdate");
// 2.3
self.queue_fire_simple_event("pause");
// TODO 2.4 (official playback position)
}
// TODO step 3 (media controller)
}
fn queue_fire_simple_event(&self, type_: &'static str) {
let win = window_from_node(self);
let task = FireSimpleEventTask::new(self, type_);
@ -260,11 +286,19 @@ impl HTMLMediaElement {
if old_ready_state <= HAVE_CURRENT_DATA {
self.queue_fire_simple_event("canplay");
//TODO: check paused state
self.queue_fire_simple_event("playing");
if !self.Paused() {
self.queue_fire_simple_event("playing");
}
}
// TODO: autoplay-related logic
if self.autoplaying.get() &&
self.Paused() &&
self.Autoplay() {
self.paused.set(false);
// TODO: show poster
self.queue_fire_simple_event("play");
self.queue_fire_simple_event("playing");
}
self.queue_fire_simple_event("canplaythrough");
}
@ -274,7 +308,7 @@ impl HTMLMediaElement {
}
// https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm
fn invoke_resource_selection_algorithm(&self, base_url: Url) {
fn invoke_resource_selection_algorithm(&self) {
// Step 1
self.network_state.set(NETWORK_NO_SOURCE);
@ -282,7 +316,8 @@ impl HTMLMediaElement {
// TODO step 3 (delay load event)
// Step 4
ScriptThread::await_stable_state(ResourceSelectionTask::new(self, base_url));
let doc = document_from_node(self);
ScriptThread::await_stable_state(ResourceSelectionTask::new(self, doc.base_url()));
}
// https://html.spec.whatwg.org/multipage/#concept-media-load-algorithm
@ -434,7 +469,9 @@ impl HTMLMediaElement {
// 4.4
self.change_ready_state(HAVE_NOTHING);
// TODO 4.5 (paused)
if !self.Paused() {
self.paused.set(true);
}
// TODO 4.6 (seeking)
// TODO 4.7 (playback position)
// TODO 4.8 (timeline offset)
@ -444,11 +481,10 @@ impl HTMLMediaElement {
// TODO step 5 (playback rate)
// Step 6
self.error.set(None);
// TODO autoplay flag
self.autoplaying.set(true);
// Step 7
let doc = document_from_node(self);
self.invoke_resource_selection_algorithm(doc.base_url());
self.invoke_resource_selection_algorithm();
// TODO step 8 (stop previously playing resource)
}
@ -463,6 +499,11 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
self.ready_state.get()
}
// https://html.spec.whatwg.org/multipage/#dom-media-autoplay
make_bool_getter!(Autoplay, "autoplay");
// https://html.spec.whatwg.org/multipage/#dom-media-autoplay
make_bool_setter!(SetAutoplay, "autoplay");
// https://html.spec.whatwg.org/multipage/#dom-media-src
make_url_getter!(Src, "src");
// https://html.spec.whatwg.org/multipage/#dom-media-src
@ -488,6 +529,60 @@ impl HTMLMediaElementMethods for HTMLMediaElement {
fn GetError(&self) -> Option<Root<MediaError>> {
self.error.get()
}
// https://html.spec.whatwg.org/multipage/#dom-media-play
fn Play(&self) {
// Step 1
if self.network_state.get() == NETWORK_EMPTY {
self.invoke_resource_selection_algorithm();
}
// TODO step 2 (seek backwards)
// TODO step 3 (media controller)
// Step 4
if self.Paused() {
// 4.1
self.paused.set(false);
// TODO 4.2 (show poster)
// 4.3
self.queue_fire_simple_event("play");
// 4.4
let state = self.ready_state.get();
if state == HAVE_NOTHING ||
state == HAVE_METADATA ||
state == HAVE_CURRENT_DATA {
self.queue_fire_simple_event("waiting");
} else {
self.queue_fire_simple_event("playing");
}
// 4.5
self.autoplaying.set(false);
// TODO 4.6 (media controller)
}
}
// https://html.spec.whatwg.org/multipage/#dom-media-pause
fn Pause(&self) {
// Step 1
if self.network_state.get() == NETWORK_EMPTY {
self.invoke_resource_selection_algorithm();
}
// Step 2
self.internal_pause_steps();
}
// https://html.spec.whatwg.org/multipage/#dom-media-paused
fn Paused(&self) -> bool {
self.paused.get()
}
}
impl VirtualMethods for HTMLMediaElement {

View file

@ -38,16 +38,16 @@ interface HTMLMediaElement : HTMLElement {
//void fastSeek(double time);
//readonly attribute unrestricted double duration;
//Date getStartDate();
//readonly attribute boolean paused;
readonly attribute boolean paused;
// attribute double defaultPlaybackRate;
// attribute double playbackRate;
//readonly attribute TimeRanges played;
//readonly attribute TimeRanges seekable;
//readonly attribute boolean ended;
// attribute boolean autoplay;
attribute boolean autoplay;
// attribute boolean loop;
//void play();
//void pause();
void play();
void pause();
// media controller
// attribute DOMString mediaGroup;

View file

@ -2646,9 +2646,6 @@
[HTMLMediaElement interface: document.createElement("video") must inherit property "getStartDate" with the proper type (23)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("video") must inherit property "paused" with the proper type (24)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("video") must inherit property "defaultPlaybackRate" with the proper type (25)]
expected: FAIL
@ -2664,18 +2661,9 @@
[HTMLMediaElement interface: document.createElement("video") must inherit property "ended" with the proper type (29)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("video") must inherit property "autoplay" with the proper type (30)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("video") must inherit property "loop" with the proper type (31)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("video") must inherit property "play" with the proper type (32)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("video") must inherit property "pause" with the proper type (33)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("video") must inherit property "mediaGroup" with the proper type (34)]
expected: FAIL
@ -2736,9 +2724,6 @@
[HTMLMediaElement interface: document.createElement("audio") must inherit property "getStartDate" with the proper type (23)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("audio") must inherit property "paused" with the proper type (24)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("audio") must inherit property "defaultPlaybackRate" with the proper type (25)]
expected: FAIL
@ -2754,18 +2739,9 @@
[HTMLMediaElement interface: document.createElement("audio") must inherit property "ended" with the proper type (29)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("audio") must inherit property "autoplay" with the proper type (30)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("audio") must inherit property "loop" with the proper type (31)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("audio") must inherit property "play" with the proper type (32)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("audio") must inherit property "pause" with the proper type (33)]
expected: FAIL
[HTMLMediaElement interface: document.createElement("audio") must inherit property "mediaGroup" with the proper type (34)]
expected: FAIL
@ -3078,9 +3054,6 @@
[HTMLMediaElement interface: operation getStartDate()]
expected: FAIL
[HTMLMediaElement interface: attribute paused]
expected: FAIL
[HTMLMediaElement interface: attribute defaultPlaybackRate]
expected: FAIL
@ -3096,18 +3069,9 @@
[HTMLMediaElement interface: attribute ended]
expected: FAIL
[HTMLMediaElement interface: attribute autoplay]
expected: FAIL
[HTMLMediaElement interface: attribute loop]
expected: FAIL
[HTMLMediaElement interface: operation play()]
expected: FAIL
[HTMLMediaElement interface: operation pause()]
expected: FAIL
[HTMLMediaElement interface: attribute mediaGroup]
expected: FAIL

View file

@ -9759,114 +9759,6 @@
[video.preload: IDL set to "AUTO" followed by IDL get]
expected: FAIL
[video.autoplay: typeof IDL attribute]
expected: FAIL
[video.autoplay: IDL get with DOM attribute unset]
expected: FAIL
[video.autoplay: setAttribute() to "" followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to " foo " followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to undefined followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to null followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to 7 followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to 1.5 followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to true followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to false followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to object "[object Object\]" followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to NaN followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to Infinity followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to -Infinity followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to "\\0" followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to object "test-toString" followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to object "test-valueOf" followed by IDL get]
expected: FAIL
[video.autoplay: setAttribute() to "autoplay" followed by IDL get]
expected: FAIL
[video.autoplay: IDL set to "" followed by hasAttribute()]
expected: FAIL
[video.autoplay: IDL set to "" followed by IDL get]
expected: FAIL
[video.autoplay: IDL set to " foo " followed by IDL get]
expected: FAIL
[video.autoplay: IDL set to undefined followed by hasAttribute()]
expected: FAIL
[video.autoplay: IDL set to undefined followed by IDL get]
expected: FAIL
[video.autoplay: IDL set to null followed by hasAttribute()]
expected: FAIL
[video.autoplay: IDL set to null followed by IDL get]
expected: FAIL
[video.autoplay: IDL set to 7 followed by IDL get]
expected: FAIL
[video.autoplay: IDL set to 1.5 followed by IDL get]
expected: FAIL
[video.autoplay: IDL set to false followed by hasAttribute()]
expected: FAIL
[video.autoplay: IDL set to object "[object Object\]" followed by IDL get]
expected: FAIL
[video.autoplay: IDL set to NaN followed by hasAttribute()]
expected: FAIL
[video.autoplay: IDL set to NaN followed by IDL get]
expected: FAIL
[video.autoplay: IDL set to Infinity followed by IDL get]
expected: FAIL
[video.autoplay: IDL set to -Infinity followed by IDL get]
expected: FAIL
[video.autoplay: IDL set to "\\0" followed by IDL get]
expected: FAIL
[video.autoplay: IDL set to object "test-toString" followed by IDL get]
expected: FAIL
[video.autoplay: IDL set to object "test-valueOf" followed by IDL get]
expected: FAIL
[video.loop: typeof IDL attribute]
expected: FAIL
@ -11907,114 +11799,6 @@
[audio.preload: IDL set to "AUTO" followed by IDL get]
expected: FAIL
[audio.autoplay: typeof IDL attribute]
expected: FAIL
[audio.autoplay: IDL get with DOM attribute unset]
expected: FAIL
[audio.autoplay: setAttribute() to "" followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to " foo " followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to undefined followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to null followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to 7 followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to 1.5 followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to true followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to false followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to object "[object Object\]" followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to NaN followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to Infinity followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to -Infinity followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to "\\0" followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to object "test-toString" followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to object "test-valueOf" followed by IDL get]
expected: FAIL
[audio.autoplay: setAttribute() to "autoplay" followed by IDL get]
expected: FAIL
[audio.autoplay: IDL set to "" followed by hasAttribute()]
expected: FAIL
[audio.autoplay: IDL set to "" followed by IDL get]
expected: FAIL
[audio.autoplay: IDL set to " foo " followed by IDL get]
expected: FAIL
[audio.autoplay: IDL set to undefined followed by hasAttribute()]
expected: FAIL
[audio.autoplay: IDL set to undefined followed by IDL get]
expected: FAIL
[audio.autoplay: IDL set to null followed by hasAttribute()]
expected: FAIL
[audio.autoplay: IDL set to null followed by IDL get]
expected: FAIL
[audio.autoplay: IDL set to 7 followed by IDL get]
expected: FAIL
[audio.autoplay: IDL set to 1.5 followed by IDL get]
expected: FAIL
[audio.autoplay: IDL set to false followed by hasAttribute()]
expected: FAIL
[audio.autoplay: IDL set to object "[object Object\]" followed by IDL get]
expected: FAIL
[audio.autoplay: IDL set to NaN followed by hasAttribute()]
expected: FAIL
[audio.autoplay: IDL set to NaN followed by IDL get]
expected: FAIL
[audio.autoplay: IDL set to Infinity followed by IDL get]
expected: FAIL
[audio.autoplay: IDL set to -Infinity followed by IDL get]
expected: FAIL
[audio.autoplay: IDL set to "\\0" followed by IDL get]
expected: FAIL
[audio.autoplay: IDL set to object "test-toString" followed by IDL get]
expected: FAIL
[audio.autoplay: IDL set to object "test-valueOf" followed by IDL get]
expected: FAIL
[audio.loop: typeof IDL attribute]
expected: FAIL

View file

@ -1,9 +0,0 @@
[event_pause.html]
type: testharness
expected: TIMEOUT
[calling pause() on autoplay audio should trigger pause event]
expected: NOTRUN
[calling pause() on autoplay video should trigger pause event]
expected: NOTRUN

View file

@ -1,15 +0,0 @@
[event_pause_noautoplay.html]
type: testharness
expected: TIMEOUT
[audio events - pause]
expected: FAIL
[calling play() then pause() on non-autoplay audio should trigger pause event]
expected: NOTRUN
[video events - pause]
expected: FAIL
[calling play() then pause() on non-autoplay video should trigger pause event]
expected: NOTRUN

View file

@ -1,9 +0,0 @@
[event_play.html]
type: testharness
expected: TIMEOUT
[setting src attribute on autoplay audio should trigger play event]
expected: NOTRUN
[setting src attribute on autoplay video should trigger play event]
expected: NOTRUN

View file

@ -1,15 +0,0 @@
[event_play_noautoplay.html]
type: testharness
expected: TIMEOUT
[audio events - play]
expected: FAIL
[calling play() on audio should trigger play event]
expected: NOTRUN
[video events - play]
expected: FAIL
[calling play() on video should trigger play event]
expected: NOTRUN

View file

@ -1,8 +0,0 @@
[event_playing_noautoplay.html]
type: testharness
[audio events - playing]
expected: FAIL
[video events - playing]
expected: FAIL

View file

@ -1,15 +1,9 @@
[event_timeupdate_noautoplay.html]
type: testharness
expected: TIMEOUT
[audio events - timeupdate]
expected: FAIL
[calling play() on a sufficiently long audio should trigger timeupdate event]
expected: NOTRUN
[video events - timeupdate]
expected: FAIL
[calling play() on a sufficiently long video should trigger timeupdate event]
expected: NOTRUN

View file

@ -1,14 +0,0 @@
[autoplay-overrides-preload.html]
type: testharness
[autoplay (set first) overrides preload "none"]
expected: FAIL
[autoplay (set last) overrides preload "none"]
expected: FAIL
[autoplay (set first) overrides preload "metadata"]
expected: FAIL
[autoplay (set last) overrides preload "metadata"]
expected: FAIL

View file

@ -1,5 +0,0 @@
[resource-selection-invoke-set-src-networkState.html]
type: testharness
[invoking load by setting src when networkState is not NETWORK_EMPTY]
expected: FAIL

View file

@ -1,9 +0,0 @@
[paused_false_during_play.html]
type: testharness
expected: TIMEOUT
[audio.paused should be false during play event]
expected: NOTRUN
[video.paused should be false during play event]
expected: NOTRUN

View file

@ -1,15 +0,0 @@
[paused_true_during_pause.html]
type: testharness
expected: TIMEOUT
[audio events - paused property]
expected: FAIL
[audio.paused should be true during pause event]
expected: NOTRUN
[video events - paused property]
expected: FAIL
[video.paused should be true during pause event]
expected: NOTRUN

View file

@ -1,5 +1,6 @@
[pause-move-to-other-document.html]
type: testharness
expected: TIMEOUT
[paused state when moving to other document]
expected: FAIL
expected: TIMEOUT

View file

@ -1,5 +1,6 @@
[pause-move-within-document.html]
type: testharness
expected: TIMEOUT
[paused state when moving within a document]
expected: FAIL
expected: TIMEOUT

View file

@ -1,5 +1,6 @@
[pause-remove-from-document-networkState.html]
type: testharness
expected: TIMEOUT
[paused state when removing from a document when networkState is NETWORK_EMPTY]
expected: FAIL
expected: TIMEOUT

View file

@ -1,5 +1,6 @@
[pause-remove-from-document.html]
type: testharness
expected: TIMEOUT
[paused state when removing from a document]
expected: FAIL
expected: TIMEOUT

View file

@ -1,5 +1,6 @@
[play-in-detached-document.html]
type: testharness
expected: TIMEOUT
[play() in detached document]
expected: FAIL
expected: TIMEOUT

View file

@ -1,32 +1,8 @@
[autoplay.html]
type: testharness
[audio.autoplay]
expected: FAIL
[audio.autoplay and load()]
expected: FAIL
[audio.autoplay and play()]
expected: FAIL
[audio.autoplay and pause()]
expected: FAIL
[audio.autoplay and internal pause steps]
expected: FAIL
[video.autoplay]
expected: FAIL
[video.autoplay and load()]
expected: FAIL
[video.autoplay and play()]
expected: FAIL
[video.autoplay and pause()]
expected: FAIL
[video.autoplay and internal pause steps]
expected: FAIL