aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2020-04-29 12:19:21 +0200
committerMartin Robinson <mrobinson@igalia.com>2020-05-01 15:29:57 +0200
commit3903c1fb98373ae08323c36e147f2f041d6f0280 (patch)
treea6f8a7ac23540c944ceefbf526a1fcf8def91968
parent6fb75c2b9eb3825932a22b1c7a6d7ce03809fbb2 (diff)
downloadservo-3903c1fb98373ae08323c36e147f2f041d6f0280.tar.gz
servo-3903c1fb98373ae08323c36e147f2f041d6f0280.zip
Add support for animationend event
This is triggered when an animation finishes. This is a high priority because it allows us to start rooting nodes with animations in the script thread. This doesn't yet cause a lot of tests to pass because they rely on the existence of `Document.getAnimations()` and the presence of `animationstart` and animationiteration` events.
-rw-r--r--components/layout/animation.rs84
-rw-r--r--components/layout/context.rs4
-rw-r--r--components/layout_thread/lib.rs22
-rw-r--r--components/script/dom/animationevent.rs76
-rw-r--r--components/script/dom/macros.rs1
-rw-r--r--components/script/dom/mod.rs1
-rw-r--r--components/script/dom/webidls/AnimationEvent.webidl26
-rw-r--r--components/script/dom/webidls/EventHandler.webidl5
-rw-r--r--components/script/dom/window.rs15
-rw-r--r--components/script/script_thread.rs147
-rw-r--r--components/script_layout_interface/message.rs2
-rw-r--r--components/script_traits/lib.rs49
-rw-r--r--components/style/animation.rs11
-rw-r--r--tests/wpt/metadata/css/css-animations/Element-getAnimations.tentative.html.ini5
-rw-r--r--tests/wpt/metadata/css/css-animations/animationevent-interface.html.ini124
-rw-r--r--tests/wpt/metadata/css/css-animations/animationevent-types.html.ini3
-rw-r--r--tests/wpt/metadata/css/css-animations/idlharness.html.ini51
-rw-r--r--tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe-shorthand.html.ini3
-rw-r--r--tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe-transform.html.ini3
-rw-r--r--tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe.html.ini3
-rw-r--r--tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe-fallback.html.ini3
-rw-r--r--tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe-multiple.html.ini3
-rw-r--r--tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe.html.ini3
-rw-r--r--tests/wpt/metadata/dom/events/webkit-animation-end-event.html.ini14
-rw-r--r--tests/wpt/metadata/dom/events/webkit-transition-end-event.html.ini3
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json2
-rw-r--r--tests/wpt/mozilla/tests/mozilla/interfaces.html1
27 files changed, 334 insertions, 330 deletions
diff --git a/components/layout/animation.rs b/components/layout/animation.rs
index 00fbf4bc1d6..64c1dfd2e0a 100644
--- a/components/layout/animation.rs
+++ b/components/layout/animation.rs
@@ -13,20 +13,20 @@ use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId;
use script_traits::UntrustedNodeAddress;
use script_traits::{
- AnimationState, ConstellationControlMsg, LayoutMsg as ConstellationMsg, TransitionEventType,
+ AnimationState, ConstellationControlMsg, LayoutMsg as ConstellationMsg,
+ TransitionOrAnimationEventType,
};
use servo_arc::Arc;
-use style::animation::{
- update_style_for_animation, Animation, ElementAnimationState, PropertyAnimation,
-};
+use style::animation::{update_style_for_animation, Animation, ElementAnimationState};
use style::dom::TElement;
use style::font_metrics::ServoMetricsProvider;
use style::selector_parser::RestyleDamage;
use style::timer::Timer;
-/// Collect newly transitioning nodes, which is used by the script process during
-/// forced, synchronous reflows to root DOM nodes for the duration of their transitions.
-pub fn collect_newly_transitioning_nodes(
+/// Collect newly animating nodes, which is used by the script process during
+/// forced, synchronous reflows to root DOM nodes for the duration of their
+/// animations or transitions.
+pub fn collect_newly_animating_nodes(
animation_states: &FxHashMap<OpaqueNode, ElementAnimationState>,
mut out: Option<&mut Vec<UntrustedNodeAddress>>,
) {
@@ -35,12 +35,7 @@ pub fn collect_newly_transitioning_nodes(
// currently stores a rooted node for every property that is transitioning.
if let Some(ref mut out) = out {
out.extend(animation_states.iter().flat_map(|(node, state)| {
- let num_transitions = state
- .new_animations
- .iter()
- .filter(|animation| animation.is_transition())
- .count();
- std::iter::repeat(node.to_untrusted_node_address()).take(num_transitions)
+ std::iter::repeat(node.to_untrusted_node_address()).take(state.new_animations.len())
}));
}
}
@@ -101,21 +96,28 @@ pub fn update_animation_state(
now: f64,
node: OpaqueNode,
) {
- let send_transition_event = |property_animation: &PropertyAnimation, event_type| {
+ let send_event = |animation: &Animation, event_type, elapsed_time| {
+ let property_or_animation_name = match *animation {
+ Animation::Transition(_, _, ref property_animation) => {
+ property_animation.property_name().into()
+ },
+ Animation::Keyframes(_, _, ref name, _) => name.to_string(),
+ };
+
script_channel
- .send(ConstellationControlMsg::TransitionEvent {
+ .send(ConstellationControlMsg::TransitionOrAnimationEvent {
pipeline_id,
event_type,
node: node.to_untrusted_node_address(),
- property_name: property_animation.property_name().into(),
- elapsed_time: property_animation.duration,
+ property_or_animation_name,
+ elapsed_time,
})
.unwrap()
};
- handle_cancelled_animations(animation_state, send_transition_event);
- handle_running_animations(animation_state, now, send_transition_event);
- handle_new_animations(animation_state, send_transition_event);
+ handle_cancelled_animations(animation_state, now, send_event);
+ handle_running_animations(animation_state, now, send_event);
+ handle_new_animations(animation_state, send_event);
}
/// Walk through the list of running animations and remove all of the ones that
@@ -123,7 +125,7 @@ pub fn update_animation_state(
pub fn handle_running_animations(
animation_state: &mut ElementAnimationState,
now: f64,
- mut send_transition_event: impl FnMut(&PropertyAnimation, TransitionEventType),
+ mut send_event: impl FnMut(&Animation, TransitionOrAnimationEventType, f64),
) {
let mut running_animations =
std::mem::replace(&mut animation_state.running_animations, Vec::new());
@@ -144,9 +146,18 @@ pub fn handle_running_animations(
animation_state.running_animations.push(running_animation);
} else {
debug!("Finishing transition: {:?}", running_animation);
- if let Animation::Transition(_, _, ref property_animation) = running_animation {
- send_transition_event(property_animation, TransitionEventType::TransitionEnd);
- }
+ let (event_type, elapsed_time) = match running_animation {
+ Animation::Transition(_, _, ref property_animation) => (
+ TransitionOrAnimationEventType::TransitionEnd,
+ property_animation.duration,
+ ),
+ Animation::Keyframes(_, _, _, ref mut state) => (
+ TransitionOrAnimationEventType::AnimationEnd,
+ state.active_duration(),
+ ),
+ };
+
+ send_event(&running_animation, event_type, elapsed_time);
animation_state.finished_animations.push(running_animation);
}
}
@@ -157,12 +168,19 @@ pub fn handle_running_animations(
/// well.
pub fn handle_cancelled_animations(
animation_state: &mut ElementAnimationState,
- mut send_transition_event: impl FnMut(&PropertyAnimation, TransitionEventType),
+ now: f64,
+ mut send_event: impl FnMut(&Animation, TransitionOrAnimationEventType, f64),
) {
for animation in animation_state.cancelled_animations.drain(..) {
match animation {
- Animation::Transition(_, _, ref property_animation) => {
- send_transition_event(property_animation, TransitionEventType::TransitionCancel)
+ Animation::Transition(_, start_time, _) => {
+ // TODO(mrobinson): We need to properly compute the elapsed_time here
+ // according to https://drafts.csswg.org/css-transitions/#event-transitionevent
+ send_event(
+ &animation,
+ TransitionOrAnimationEventType::TransitionCancel,
+ (now - start_time).max(0.),
+ );
},
// TODO(mrobinson): We should send animationcancel events.
Animation::Keyframes(..) => {},
@@ -172,12 +190,18 @@ pub fn handle_cancelled_animations(
pub fn handle_new_animations(
animation_state: &mut ElementAnimationState,
- mut send_transition_event: impl FnMut(&PropertyAnimation, TransitionEventType),
+ mut send_event: impl FnMut(&Animation, TransitionOrAnimationEventType, f64),
) {
for animation in animation_state.new_animations.drain(..) {
match animation {
- Animation::Transition(_, _, ref property_animation) => {
- send_transition_event(property_animation, TransitionEventType::TransitionRun)
+ Animation::Transition(..) => {
+ // TODO(mrobinson): We need to properly compute the elapsed_time here
+ // according to https://drafts.csswg.org/css-transitions/#event-transitionevent
+ send_event(
+ &animation,
+ TransitionOrAnimationEventType::TransitionRun,
+ 0.,
+ )
},
Animation::Keyframes(..) => {},
}
diff --git a/components/layout/context.rs b/components/layout/context.rs
index f98f8bc8395..fc243b8234f 100644
--- a/components/layout/context.rs
+++ b/components/layout/context.rs
@@ -86,9 +86,9 @@ pub struct LayoutContext<'a> {
/// A None value means that this layout was not initiated by the script thread.
pub pending_images: Option<Mutex<Vec<PendingImage>>>,
- /// A list of nodes that have just initiated a CSS transition.
+ /// A list of nodes that have just initiated a CSS transition or animation.
/// A None value means that this layout was not initiated by the script thread.
- pub newly_transitioning_nodes: Option<Mutex<Vec<UntrustedNodeAddress>>>,
+ pub newly_animating_nodes: Option<Mutex<Vec<UntrustedNodeAddress>>>,
}
impl<'a> Drop for LayoutContext<'a> {
diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs
index 4a346315e8a..046a9a6f30e 100644
--- a/components/layout_thread/lib.rs
+++ b/components/layout_thread/lib.rs
@@ -648,7 +648,7 @@ impl LayoutThread {
} else {
None
},
- newly_transitioning_nodes: if script_initiated_layout {
+ newly_animating_nodes: if script_initiated_layout {
Some(Mutex::new(vec![]))
} else {
None
@@ -1565,11 +1565,11 @@ impl LayoutThread {
};
reflow_result.pending_images = pending_images;
- let newly_transitioning_nodes = match context.newly_transitioning_nodes {
+ let newly_animating_nodes = match context.newly_animating_nodes {
Some(ref nodes) => std::mem::replace(&mut *nodes.lock().unwrap(), vec![]),
None => vec![],
};
- reflow_result.newly_transitioning_nodes = newly_transitioning_nodes;
+ reflow_result.newly_animating_nodes = newly_animating_nodes;
let mut root_flow = match self.root_flow.borrow().clone() {
Some(root_flow) => root_flow,
@@ -1741,7 +1741,7 @@ impl LayoutThread {
invalid_nodes,
);
assert!(layout_context.pending_images.is_none());
- assert!(layout_context.newly_transitioning_nodes.is_none());
+ assert!(layout_context.newly_animating_nodes.is_none());
}
}
@@ -1756,19 +1756,13 @@ impl LayoutThread {
invalid_nodes: FxHashSet<OpaqueNode>,
) {
{
- let mut newly_transitioning_nodes = context
- .newly_transitioning_nodes
+ let mut newly_animating_nodes = context
+ .newly_animating_nodes
.as_ref()
.map(|nodes| nodes.lock().unwrap());
- let newly_transitioning_nodes =
- newly_transitioning_nodes.as_mut().map(|nodes| &mut **nodes);
+ let newly_animating_nodes = newly_animating_nodes.as_mut().map(|nodes| &mut **nodes);
let mut animation_states = self.animation_states.write();
-
- animation::collect_newly_transitioning_nodes(
- &animation_states,
- newly_transitioning_nodes,
- );
-
+ animation::collect_newly_animating_nodes(&animation_states, newly_animating_nodes);
animation::update_animation_states(
&self.constellation_chan,
&self.script_chan,
diff --git a/components/script/dom/animationevent.rs b/components/script/dom/animationevent.rs
new file mode 100644
index 00000000000..191b460228d
--- /dev/null
+++ b/components/script/dom/animationevent.rs
@@ -0,0 +1,76 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::codegen::Bindings::AnimationEventBinding::{
+ AnimationEventInit, AnimationEventMethods,
+};
+use crate::dom::bindings::codegen::Bindings::EventBinding::EventMethods;
+use crate::dom::bindings::inheritance::Castable;
+use crate::dom::bindings::num::Finite;
+use crate::dom::bindings::reflector::reflect_dom_object;
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::event::Event;
+use crate::dom::window::Window;
+use dom_struct::dom_struct;
+use servo_atoms::Atom;
+
+#[dom_struct]
+pub struct AnimationEvent {
+ event: Event,
+ animation_name: Atom,
+ elapsed_time: Finite<f32>,
+ pseudo_element: DOMString,
+}
+
+impl AnimationEvent {
+ fn new_inherited(init: &AnimationEventInit) -> AnimationEvent {
+ AnimationEvent {
+ event: Event::new_inherited(),
+ animation_name: Atom::from(init.animationName.clone()),
+ elapsed_time: init.elapsedTime.clone(),
+ pseudo_element: init.pseudoElement.clone(),
+ }
+ }
+
+ pub fn new(window: &Window, type_: Atom, init: &AnimationEventInit) -> DomRoot<AnimationEvent> {
+ let ev = reflect_dom_object(Box::new(AnimationEvent::new_inherited(init)), window);
+ {
+ let event = ev.upcast::<Event>();
+ event.init_event(type_, init.parent.bubbles, init.parent.cancelable);
+ }
+ ev
+ }
+
+ #[allow(non_snake_case)]
+ pub fn Constructor(
+ window: &Window,
+ type_: DOMString,
+ init: &AnimationEventInit,
+ ) -> DomRoot<AnimationEvent> {
+ AnimationEvent::new(window, Atom::from(type_), init)
+ }
+}
+
+impl AnimationEventMethods for AnimationEvent {
+ // https://drafts.csswg.org/css-animations/#interface-animationevent-attributes
+ fn AnimationName(&self) -> DOMString {
+ DOMString::from(&*self.animation_name)
+ }
+
+ // https://drafts.csswg.org/css-animations/#interface-animationevent-attributes
+ fn ElapsedTime(&self) -> Finite<f32> {
+ self.elapsed_time.clone()
+ }
+
+ // https://drafts.csswg.org/css-animations/#interface-animationevent-attributes
+ fn PseudoElement(&self) -> DOMString {
+ self.pseudo_element.clone()
+ }
+
+ // https://dom.spec.whatwg.org/#dom-event-istrusted
+ fn IsTrusted(&self) -> bool {
+ self.upcast::<Event>().IsTrusted()
+ }
+}
diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs
index b1ea4f5cde2..871e831dc82 100644
--- a/components/script/dom/macros.rs
+++ b/components/script/dom/macros.rs
@@ -442,6 +442,7 @@ macro_rules! global_event_handlers(
);
(NoOnload) => (
event_handler!(abort, GetOnabort, SetOnabort);
+ event_handler!(animationend, GetOnanimationend, SetOnanimationend);
event_handler!(cancel, GetOncancel, SetOncancel);
event_handler!(canplay, GetOncanplay, SetOncanplay);
event_handler!(canplaythrough, GetOncanplaythrough, SetOncanplaythrough);
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index a0f6241d55e..9536f113417 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -213,6 +213,7 @@ pub mod abstractworker;
pub mod abstractworkerglobalscope;
pub mod activation;
pub mod analysernode;
+pub mod animationevent;
pub mod attr;
pub mod audiobuffer;
pub mod audiobuffersourcenode;
diff --git a/components/script/dom/webidls/AnimationEvent.webidl b/components/script/dom/webidls/AnimationEvent.webidl
new file mode 100644
index 00000000000..fd9d6c47f7e
--- /dev/null
+++ b/components/script/dom/webidls/AnimationEvent.webidl
@@ -0,0 +1,26 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/.
+ *
+ * The origin of this IDL file is
+ * http://www.w3.org/TR/css3-animations/#animation-events-
+ * http://dev.w3.org/csswg/css3-animations/#animation-events-
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[Exposed=Window]
+interface AnimationEvent : Event {
+ constructor(DOMString type, optional AnimationEventInit eventInitDict = {});
+
+ readonly attribute DOMString animationName;
+ readonly attribute float elapsedTime;
+ readonly attribute DOMString pseudoElement;
+};
+
+dictionary AnimationEventInit : EventInit {
+ DOMString animationName = "";
+ float elapsedTime = 0;
+ DOMString pseudoElement = "";
+};
diff --git a/components/script/dom/webidls/EventHandler.webidl b/components/script/dom/webidls/EventHandler.webidl
index a3514182806..b5617564fbc 100644
--- a/components/script/dom/webidls/EventHandler.webidl
+++ b/components/script/dom/webidls/EventHandler.webidl
@@ -90,6 +90,11 @@ interface mixin GlobalEventHandlers {
attribute EventHandler onwaiting;
};
+// https://drafts.csswg.org/css-animations/#interface-globaleventhandlers-idl
+partial interface mixin GlobalEventHandlers {
+ attribute EventHandler onanimationend;
+};
+
// https://drafts.csswg.org/css-transitions/#interface-globaleventhandlers-idl
partial interface mixin GlobalEventHandlers {
attribute EventHandler ontransitionrun;
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index e6d8c1bd13f..ccb4b8dfb48 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -1582,11 +1582,11 @@ impl Window {
}
let for_display = reflow_goal == ReflowGoal::Full;
+ let pipeline_id = self.upcast::<GlobalScope>().pipeline_id();
if for_display && self.suppress_reflow.get() {
debug!(
"Suppressing reflow pipeline {} for reason {:?} before FirstLoad or RefreshTick",
- self.upcast::<GlobalScope>().pipeline_id(),
- reason
+ pipeline_id, reason
);
return false;
}
@@ -1617,11 +1617,7 @@ impl Window {
// On debug mode, print the reflow event information.
if self.relayout_event {
- debug_reflow_events(
- self.upcast::<GlobalScope>().pipeline_id(),
- &reflow_goal,
- &reason,
- );
+ debug_reflow_events(pipeline_id, &reflow_goal, &reason);
}
let document = self.Document();
@@ -1699,12 +1695,11 @@ impl Window {
{
let (responder, responder_listener) =
ProfiledIpc::channel(self.global().time_profiler_chan().clone()).unwrap();
- let pipeline = self.upcast::<GlobalScope>().pipeline_id();
let image_cache_chan = self.image_cache_chan.clone();
ROUTER.add_route(
responder_listener.to_opaque(),
Box::new(move |message| {
- let _ = image_cache_chan.send((pipeline, message.to().unwrap()));
+ let _ = image_cache_chan.send((pipeline_id, message.to().unwrap()));
}),
);
self.image_cache
@@ -1714,7 +1709,7 @@ impl Window {
}
unsafe {
- ScriptThread::note_newly_transitioning_nodes(complete.newly_transitioning_nodes);
+ ScriptThread::note_newly_animating_nodes(pipeline_id, complete.newly_animating_nodes);
}
true
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 16fd866f1b9..165e526fa76 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -19,7 +19,9 @@
use crate::devtools;
use crate::document_loader::DocumentLoader;
+use crate::dom::animationevent::AnimationEvent;
use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::AnimationEventBinding::AnimationEventInit;
use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
DocumentMethods, DocumentReadyState,
};
@@ -138,9 +140,9 @@ use script_traits::{
EventResult, HistoryEntryReplacement, InitialScriptState, JsEvalResult, LayoutMsg, LoadData,
LoadOrigin, MediaSessionActionType, MouseButton, MouseEventType, NewLayoutInfo, Painter,
ProgressiveWebMetricType, ScriptMsg, ScriptThreadFactory, ScriptToConstellationChan,
- StructuredSerializedData, TimerSchedulerMsg, TouchEventType, TouchId, TransitionEventType,
- UntrustedNodeAddress, UpdatePipelineIdReason, WebrenderIpcSender, WheelDelta, WindowSizeData,
- WindowSizeType,
+ StructuredSerializedData, TimerSchedulerMsg, TouchEventType, TouchId,
+ TransitionOrAnimationEventType, UntrustedNodeAddress, UpdatePipelineIdReason,
+ WebrenderIpcSender, WheelDelta, WindowSizeData, WindowSizeType,
};
use servo_atoms::Atom;
use servo_config::opts;
@@ -639,7 +641,7 @@ pub struct ScriptThread {
/// A list of nodes with in-progress CSS transitions, which roots them for the duration
/// of the transition.
- transitioning_nodes: DomRefCell<Vec<Dom<Node>>>,
+ animating_nodes: DomRefCell<HashMap<PipelineId, Vec<Dom<Node>>>>,
/// <https://html.spec.whatwg.org/multipage/#custom-element-reactions-stack>
custom_element_reaction_stack: CustomElementReactionStack,
@@ -823,7 +825,10 @@ impl ScriptThread {
})
}
- pub unsafe fn note_newly_transitioning_nodes(nodes: Vec<UntrustedNodeAddress>) {
+ pub unsafe fn note_newly_animating_nodes(
+ pipeline_id: PipelineId,
+ nodes: Vec<UntrustedNodeAddress>,
+ ) {
SCRIPT_THREAD_ROOT.with(|root| {
let script_thread = &*root.get().unwrap();
let js_runtime = script_thread.js_runtime.rt();
@@ -831,8 +836,10 @@ impl ScriptThread {
.into_iter()
.map(|n| Dom::from_ref(&*from_untrusted_node_address(js_runtime, n)));
script_thread
- .transitioning_nodes
+ .animating_nodes
.borrow_mut()
+ .entry(pipeline_id)
+ .or_insert_with(Vec::new)
.extend(new_nodes);
})
}
@@ -1345,7 +1352,7 @@ impl ScriptThread {
docs_with_no_blocking_loads: Default::default(),
- transitioning_nodes: Default::default(),
+ animating_nodes: Default::default(),
custom_element_reaction_stack: CustomElementReactionStack::new(),
@@ -1697,7 +1704,7 @@ impl ScriptThread {
FocusIFrame(id, ..) => Some(id),
WebDriverScriptCommand(id, ..) => Some(id),
TickAllAnimations(id) => Some(id),
- TransitionEvent { .. } => None,
+ TransitionOrAnimationEvent { .. } => None,
WebFontLoaded(id) => Some(id),
DispatchIFrameLoadEvent {
target: _,
@@ -1898,18 +1905,18 @@ impl ScriptThread {
ConstellationControlMsg::TickAllAnimations(pipeline_id) => {
self.handle_tick_all_animations(pipeline_id)
},
- ConstellationControlMsg::TransitionEvent {
+ ConstellationControlMsg::TransitionOrAnimationEvent {
pipeline_id,
event_type,
node,
- property_name,
+ property_or_animation_name,
elapsed_time,
} => {
- self.handle_transition_event(
+ self.handle_transition_or_animation_event(
pipeline_id,
event_type,
node,
- property_name,
+ property_or_animation_name,
elapsed_time,
);
},
@@ -2846,6 +2853,9 @@ impl ScriptThread {
.send((id, ScriptMsg::PipelineExited))
.ok();
+ // Remove any rooted nodes for active animations and transitions.
+ self.animating_nodes.borrow_mut().remove(&id);
+
// Now that layout is shut down, it's OK to remove the document.
if let Some(document) = document {
// We don't want to dispatch `mouseout` event pointing to non-existing element
@@ -2916,66 +2926,91 @@ impl ScriptThread {
/// Handles firing of transition-related events.
///
/// TODO(mrobinson): Add support for more events.
- fn handle_transition_event(
+ fn handle_transition_or_animation_event(
&self,
pipeline_id: PipelineId,
- event_type: TransitionEventType,
+ event_type: TransitionOrAnimationEventType,
unsafe_node: UntrustedNodeAddress,
- property_name: String,
+ property_or_animation_name: String,
elapsed_time: f64,
) {
let js_runtime = self.js_runtime.rt();
let node = unsafe { from_untrusted_node_address(js_runtime, unsafe_node) };
- let node_index = self
- .transitioning_nodes
- .borrow()
- .iter()
- .position(|n| &**n as *const _ == &*node as *const _);
- let node_index = match node_index {
- Some(node_index) => node_index,
- None => {
- // If no index is found, we can't know whether this node is safe to use.
- // It's better not to fire a DOM event than crash.
- warn!("Ignoring transition end notification for unknown node.");
- return;
- },
- };
+ // We limit the scope of the borrow here, so that we don't maintain this borrow
+ // and then incidentally trigger another layout. That might result in a double
+ // mutable borrow of `animating_nodes`.
+ {
+ let mut animating_nodes = self.animating_nodes.borrow_mut();
+ let nodes = match animating_nodes.get_mut(&pipeline_id) {
+ Some(nodes) => nodes,
+ None => {
+ return warn!(
+ "Ignoring transition event for pipeline without animating nodes."
+ );
+ },
+ };
- if self.closed_pipelines.borrow().contains(&pipeline_id) {
- warn!("Ignoring transition event for closed pipeline.");
- return;
+ let node_index = nodes
+ .iter()
+ .position(|n| &**n as *const _ == &*node as *const _);
+ let node_index = match node_index {
+ Some(node_index) => node_index,
+ None => {
+ // If no index is found, we can't know whether this node is safe to use.
+ // It's better not to fire a DOM event than crash.
+ warn!("Ignoring transition event for unknown node.");
+ return;
+ },
+ };
+
+ if event_type.finalizes_transition_or_animation() {
+ nodes.remove(node_index);
+ }
+ }
+
+ // Not quite the right thing - see #13865.
+ if event_type.finalizes_transition_or_animation() {
+ node.dirty(NodeDamage::NodeStyleDamaged);
}
let event_atom = match event_type {
- TransitionEventType::TransitionRun => atom!("transitionrun"),
- TransitionEventType::TransitionEnd => {
- // Not quite the right thing - see #13865.
- node.dirty(NodeDamage::NodeStyleDamaged);
- self.transitioning_nodes.borrow_mut().remove(node_index);
- atom!("transitionend")
- },
- TransitionEventType::TransitionCancel => {
- self.transitioning_nodes.borrow_mut().remove(node_index);
- atom!("transitioncancel")
- },
+ TransitionOrAnimationEventType::AnimationEnd => atom!("animationend"),
+ TransitionOrAnimationEventType::TransitionCancel => atom!("transitioncancel"),
+ TransitionOrAnimationEventType::TransitionEnd => atom!("transitionend"),
+ TransitionOrAnimationEventType::TransitionRun => atom!("transitionrun"),
};
-
- let event_init = TransitionEventInit {
- parent: EventInit {
- bubbles: true,
- cancelable: false,
- },
- propertyName: DOMString::from(property_name),
- elapsedTime: Finite::new(elapsed_time as f32).unwrap(),
- // TODO: Handle pseudo-elements properly
- pseudoElement: DOMString::new(),
+ let parent = EventInit {
+ bubbles: true,
+ cancelable: false,
};
+ // TODO: Handle pseudo-elements properly
+ let property_or_animation_name = DOMString::from(property_or_animation_name);
+ let elapsed_time = Finite::new(elapsed_time as f32).unwrap();
let window = window_from_node(&*node);
- TransitionEvent::new(&window, event_atom, &event_init)
- .upcast::<Event>()
- .fire(node.upcast());
+
+ if event_type.is_transition_event() {
+ let event_init = TransitionEventInit {
+ parent,
+ propertyName: property_or_animation_name,
+ elapsedTime: elapsed_time,
+ pseudoElement: DOMString::new(),
+ };
+ TransitionEvent::new(&window, event_atom, &event_init)
+ .upcast::<Event>()
+ .fire(node.upcast());
+ } else {
+ let event_init = AnimationEventInit {
+ parent,
+ animationName: property_or_animation_name,
+ elapsedTime: elapsed_time,
+ pseudoElement: DOMString::new(),
+ };
+ AnimationEvent::new(&window, event_atom, &event_init)
+ .upcast::<Event>()
+ .fire(node.upcast());
+ }
}
/// Handles a Web font being loaded. Does nothing if the page no longer exists.
diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs
index 63854134cac..fe117436b51 100644
--- a/components/script_layout_interface/message.rs
+++ b/components/script_layout_interface/message.rs
@@ -193,7 +193,7 @@ pub struct ReflowComplete {
/// The list of images that were encountered that are in progress.
pub pending_images: Vec<PendingImage>,
/// The list of nodes that initiated a CSS transition.
- pub newly_transitioning_nodes: Vec<UntrustedNodeAddress>,
+ pub newly_animating_nodes: Vec<UntrustedNodeAddress>,
}
/// Information needed for a script-initiated reflow.
diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs
index 3db883b6536..c23221f929f 100644
--- a/components/script_traits/lib.rs
+++ b/components/script_traits/lib.rs
@@ -282,16 +282,40 @@ pub enum UpdatePipelineIdReason {
Traversal,
}
-/// The type of transition event to trigger.
+/// The type of transition event to trigger. These are defined by
+/// CSS Transitions § 6.1 and CSS Animations § 4.2
#[derive(Clone, Debug, Deserialize, Serialize)]
-pub enum TransitionEventType {
- /// The transition has started running.
+pub enum TransitionOrAnimationEventType {
+ /// "The transitionrun event occurs when a transition is created (i.e., when it
+ /// is added to the set of running transitions)."
TransitionRun,
- /// The transition has ended by reaching the end of its animation.
+ /// "The transitionend event occurs at the completion of the transition. In the
+ /// case where a transition is removed before completion, such as if the
+ /// transition-property is removed, then the event will not fire."
TransitionEnd,
- /// The transition ended early for some reason, such as the property
- /// no longer being transitionable or being replaced by another transition.
+ /// "The transitioncancel event occurs when a transition is canceled."
TransitionCancel,
+ /// "The animationend event occurs when the animation finishes"
+ AnimationEnd,
+}
+
+impl TransitionOrAnimationEventType {
+ /// Whether or not this event finalizes the animation or transition. During finalization
+ /// the DOM object associated with this transition or animation is unrooted.
+ pub fn finalizes_transition_or_animation(&self) -> bool {
+ match *self {
+ Self::TransitionEnd | Self::TransitionCancel | Self::AnimationEnd => true,
+ Self::TransitionRun => false,
+ }
+ }
+
+ /// Whether or not this event is a transition-related event.
+ pub fn is_transition_event(&self) -> bool {
+ match *self {
+ Self::TransitionRun | Self::TransitionEnd | Self::TransitionCancel => true,
+ Self::AnimationEnd => false,
+ }
+ }
}
/// Messages sent from the constellation or layout to the script thread.
@@ -380,16 +404,17 @@ pub enum ConstellationControlMsg {
WebDriverScriptCommand(PipelineId, WebDriverScriptCommand),
/// Notifies script thread that all animations are done
TickAllAnimations(PipelineId),
- /// Notifies the script thread that a transition related event should be sent.
- TransitionEvent {
+ /// Notifies the script thread that a transition or animation related event should be sent.
+ TransitionOrAnimationEvent {
/// The pipeline id of the layout task that sent this message.
pipeline_id: PipelineId,
/// The type of transition event this should trigger.
- event_type: TransitionEventType,
+ event_type: TransitionOrAnimationEventType,
/// The address of the node which owns this transition.
node: UntrustedNodeAddress,
- /// The property name of the property that is transitioning.
- property_name: String,
+ /// The name of the property that is transitioning (in the case of a transition)
+ /// or the name of the animation (in the case of an animation).
+ property_or_animation_name: String,
/// The elapsed time property to send with this transition event.
elapsed_time: f64,
},
@@ -452,7 +477,7 @@ impl fmt::Debug for ConstellationControlMsg {
FocusIFrame(..) => "FocusIFrame",
WebDriverScriptCommand(..) => "WebDriverScriptCommand",
TickAllAnimations(..) => "TickAllAnimations",
- TransitionEvent { .. } => "TransitionEvent",
+ TransitionOrAnimationEvent { .. } => "TransitionOrAnimationEvent",
WebFontLoaded(..) => "WebFontLoaded",
DispatchIFrameLoadEvent { .. } => "DispatchIFrameLoadEvent",
DispatchStorageEvent(..) => "DispatchStorageEvent",
diff --git a/components/style/animation.rs b/components/style/animation.rs
index 59c9f847e96..eed3aaada1a 100644
--- a/components/style/animation.rs
+++ b/components/style/animation.rs
@@ -172,6 +172,17 @@ impl KeyframesAnimationState {
self.current_direction = old_direction;
self.started_at = new_started_at;
}
+
+ /// Calculate the active-duration of this animation according to
+ /// https://drafts.csswg.org/css-animations/#active-duration. active-duration
+ /// is not really meaningful for infinite animations so we just return 0
+ /// here in that case.
+ pub fn active_duration(&self) -> f64 {
+ match self.iteration_state {
+ KeyframesIterationState::Finite(_, max) => self.duration * (max as f64),
+ KeyframesIterationState::Infinite => 0.,
+ }
+ }
}
impl fmt::Debug for KeyframesAnimationState {
diff --git a/tests/wpt/metadata/css/css-animations/Element-getAnimations.tentative.html.ini b/tests/wpt/metadata/css/css-animations/Element-getAnimations.tentative.html.ini
index bf27b93175b..854c8c6e480 100644
--- a/tests/wpt/metadata/css/css-animations/Element-getAnimations.tentative.html.ini
+++ b/tests/wpt/metadata/css/css-animations/Element-getAnimations.tentative.html.ini
@@ -1,6 +1,5 @@
[Element-getAnimations.tentative.html]
bug: https://github.com/servo/servo/issues/21564
- expected: TIMEOUT
[getAnimations for CSS Animations with animation-name: none]
expected: FAIL
@@ -35,7 +34,7 @@
expected: FAIL
[getAnimations for CSS Animations that have finished but are forwards filling]
- expected: TIMEOUT
+ expected: FAIL
[getAnimations returns objects with the same identity]
expected: FAIL
@@ -56,7 +55,7 @@
expected: FAIL
[getAnimations for CSS Animations that have finished]
- expected: TIMEOUT
+ expected: FAIL
[{ subtree: false } on a leaf element returns the element's animations and ignore pseudo-elements]
expected: FAIL
diff --git a/tests/wpt/metadata/css/css-animations/animationevent-interface.html.ini b/tests/wpt/metadata/css/css-animations/animationevent-interface.html.ini
deleted file mode 100644
index a4d160df59e..00000000000
--- a/tests/wpt/metadata/css/css-animations/animationevent-interface.html.ini
+++ /dev/null
@@ -1,124 +0,0 @@
-[animationevent-interface.html]
- [the event is an instance of AnimationEvent]
- expected: FAIL
-
- [animationName is readonly]
- expected: FAIL
-
- [type argument is null]
- expected: FAIL
-
- [elapsedTime has default value of 0.0]
- expected: FAIL
-
- [elapsedTime is readonly]
- expected: FAIL
-
- [elapsedTime set to 0.5]
- expected: FAIL
-
- [animationEventInit argument is empty dictionary]
- expected: FAIL
-
- [event type set to undefined]
- expected: FAIL
-
- [Missing type argument]
- expected: FAIL
-
- [AnimationEvent.pseudoElement initialized from the dictionary]
- expected: FAIL
-
- [the event inherts from Event]
- expected: FAIL
-
- [type argument is string]
- expected: FAIL
-
- [animationName set to 'sample']
- expected: FAIL
-
- [animationEventInit argument is undefined]
- expected: FAIL
-
- [animationEventInit argument is null]
- expected: FAIL
-
- [AnimationEventInit properties set value]
- expected: FAIL
-
- [animationName has default value of empty string]
- expected: FAIL
-
- [elapsedTime set to -0.5]
- expected: FAIL
-
- [elapsedTime cannot be set to -Infinity]
- expected: FAIL
-
- [elapsedTime cannot be set to Infinity]
- expected: FAIL
-
- [animationName set to [\]]
- expected: FAIL
-
- [elapsedTime set to null]
- expected: FAIL
-
- [elapsedTime set to an object with a valueOf function]
- expected: FAIL
-
- [animationName set to an object with a valueOf function]
- expected: FAIL
-
- [elapsedTime cannot be set to NaN]
- expected: FAIL
-
- [elapsedTime set to true]
- expected: FAIL
-
- [elapsedTime set to '']
- expected: FAIL
-
- [elapsedTime set to [0.5\]]
- expected: FAIL
-
- [elapsedTime set to undefined]
- expected: FAIL
-
- [animationName set to true]
- expected: FAIL
-
- [elapsedTime set to false]
- expected: FAIL
-
- [elapsedTime set to [\]]
- expected: FAIL
-
- [elapsedTime cannot be set to [0.5, 1.0\]]
- expected: FAIL
-
- [animationName set to null]
- expected: FAIL
-
- [animationName set to an object]
- expected: FAIL
-
- [elapsedTime cannot be set to 'sample']
- expected: FAIL
-
- [animationName set to undefined]
- expected: FAIL
-
- [animationName set to [1, 2, 3\]]
- expected: FAIL
-
- [animationName set to false]
- expected: FAIL
-
- [animationName set to a number]
- expected: FAIL
-
- [elapsedTime cannot be set to an object]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/css/css-animations/animationevent-types.html.ini b/tests/wpt/metadata/css/css-animations/animationevent-types.html.ini
index 9a5d66fd1ef..70ed3998119 100644
--- a/tests/wpt/metadata/css/css-animations/animationevent-types.html.ini
+++ b/tests/wpt/metadata/css/css-animations/animationevent-types.html.ini
@@ -4,9 +4,6 @@
[animationiteration event is instanceof AnimationEvent]
expected: TIMEOUT
- [animationend event is instanceof AnimationEvent]
- expected: TIMEOUT
-
[animationstart event is instanceof AnimationEvent]
expected: TIMEOUT
diff --git a/tests/wpt/metadata/css/css-animations/idlharness.html.ini b/tests/wpt/metadata/css/css-animations/idlharness.html.ini
index 01e1d42bf7f..6b8f7e14289 100644
--- a/tests/wpt/metadata/css/css-animations/idlharness.html.ini
+++ b/tests/wpt/metadata/css/css-animations/idlharness.html.ini
@@ -1,61 +1,25 @@
[idlharness.html]
- [AnimationEvent interface: attribute pseudoElement]
- expected: FAIL
-
- [AnimationEvent interface: existence and properties of interface prototype object]
- expected: FAIL
-
- [Window interface: attribute onanimationend]
- expected: FAIL
-
[Document interface: attribute onanimationiteration]
expected: FAIL
- [AnimationEvent interface object length]
- expected: FAIL
-
[CSSKeyframeRule interface: attribute style]
expected: FAIL
- [AnimationEvent interface object name]
- expected: FAIL
-
- [AnimationEvent interface: attribute elapsedTime]
- expected: FAIL
-
[Document interface: attribute onanimationstart]
expected: FAIL
[HTMLElement interface: attribute onanimationiteration]
expected: FAIL
- [AnimationEvent must be primary interface of new AnimationEvent("animationstart")]
- expected: FAIL
-
- [AnimationEvent interface: existence and properties of interface prototype object's @@unscopables property]
- expected: FAIL
-
[Window interface: attribute onanimationcancel]
expected: FAIL
[CSSKeyframeRule interface: attribute keyText]
expected: FAIL
- [AnimationEvent interface: new AnimationEvent("animationstart") must inherit property "pseudoElement" with the proper type]
- expected: FAIL
-
- [Stringification of new AnimationEvent("animationstart")]
- expected: FAIL
-
- [Document interface: attribute onanimationend]
- expected: FAIL
-
[HTMLElement interface: attribute onanimationstart]
expected: FAIL
- [AnimationEvent interface: new AnimationEvent("animationstart") must inherit property "animationName" with the proper type]
- expected: FAIL
-
[Document interface: attribute onanimationcancel]
expected: FAIL
@@ -65,24 +29,9 @@
[HTMLElement interface: attribute onanimationcancel]
expected: FAIL
- [AnimationEvent interface: attribute animationName]
- expected: FAIL
-
[Window interface: attribute onanimationiteration]
expected: FAIL
- [AnimationEvent interface: new AnimationEvent("animationstart") must inherit property "elapsedTime" with the proper type]
- expected: FAIL
-
[CSSKeyframeRule interface: keyframes.cssRules[0\] must inherit property "keyText" with the proper type]
expected: FAIL
- [AnimationEvent interface: existence and properties of interface prototype object's "constructor" property]
- expected: FAIL
-
- [AnimationEvent interface: existence and properties of interface object]
- expected: FAIL
-
- [HTMLElement interface: attribute onanimationend]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe-shorthand.html.ini b/tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe-shorthand.html.ini
index baa566691e6..5d6b41c4332 100644
--- a/tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe-shorthand.html.ini
+++ b/tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe-shorthand.html.ini
@@ -1,9 +1,8 @@
[variable-animation-substitute-into-keyframe-shorthand.html]
bug: https://github.com/servo/servo/issues/21564
- expected: TIMEOUT
[Verify border-bottom-color before animation]
expected: FAIL
[Verify border-bottom-color after animation]
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe-transform.html.ini b/tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe-transform.html.ini
index 83d7114a33c..77ff1af8a7d 100644
--- a/tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe-transform.html.ini
+++ b/tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe-transform.html.ini
@@ -1,9 +1,8 @@
[variable-animation-substitute-into-keyframe-transform.html]
bug: https://github.com/servo/servo/issues/21564
- expected: TIMEOUT
[Verify transform before animation]
expected: FAIL
[Verify transform after animation]
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe.html.ini b/tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe.html.ini
index 1e19344cbec..225a08b98ac 100644
--- a/tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe.html.ini
+++ b/tests/wpt/metadata/css/css-variables/variable-animation-substitute-into-keyframe.html.ini
@@ -1,9 +1,8 @@
[variable-animation-substitute-into-keyframe.html]
bug: https://github.com/servo/servo/issues/21564
- expected: TIMEOUT
[Verify color before animation]
expected: FAIL
[Verify color after animation]
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe-fallback.html.ini b/tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe-fallback.html.ini
index ec903a327a8..a0f8055196a 100644
--- a/tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe-fallback.html.ini
+++ b/tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe-fallback.html.ini
@@ -1,9 +1,8 @@
[variable-animation-substitute-within-keyframe-fallback.html]
bug: https://github.com/servo/servo/issues/21564
- expected: TIMEOUT
[Verify color before animation]
expected: FAIL
[Verify color after animation]
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe-multiple.html.ini b/tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe-multiple.html.ini
index d4f2fefef86..baa8d60195e 100644
--- a/tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe-multiple.html.ini
+++ b/tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe-multiple.html.ini
@@ -1,9 +1,8 @@
[variable-animation-substitute-within-keyframe-multiple.html]
bug: https://github.com/servo/servo/issues/21564
- expected: TIMEOUT
[Verify color before animation]
expected: FAIL
[Verify color after animation]
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe.html.ini b/tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe.html.ini
index 6d7eafff16b..e1e48b487e4 100644
--- a/tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe.html.ini
+++ b/tests/wpt/metadata/css/css-variables/variable-animation-substitute-within-keyframe.html.ini
@@ -1,9 +1,8 @@
[variable-animation-substitute-within-keyframe.html]
bug: https://github.com/servo/servo/issues/21564
- expected: TIMEOUT
[Verify color before animation]
expected: FAIL
[Verify color after animation]
- expected: TIMEOUT
+ expected: FAIL
diff --git a/tests/wpt/metadata/dom/events/webkit-animation-end-event.html.ini b/tests/wpt/metadata/dom/events/webkit-animation-end-event.html.ini
index c560f81d9b6..2b8b4ec6d09 100644
--- a/tests/wpt/metadata/dom/events/webkit-animation-end-event.html.ini
+++ b/tests/wpt/metadata/dom/events/webkit-animation-end-event.html.ini
@@ -1,4 +1,5 @@
[webkit-animation-end-event.html]
+ expected: TIMEOUT
[event types for prefixed and unprefixed animationend event handlers should be named appropriately]
expected: FAIL
@@ -6,13 +7,13 @@
expected: FAIL
[webkitAnimationEnd event listener should not trigger if an unprefixed event handler also exists]
- expected: FAIL
+ expected: NOTRUN
[webkitAnimationEnd event listener is case sensitive]
- expected: FAIL
+ expected: NOTRUN
[webkitAnimationEnd event listener should trigger for an animation]
- expected: FAIL
+ expected: TIMEOUT
[onwebkitanimationend event handler should trigger for an animation]
expected: FAIL
@@ -20,20 +21,17 @@
[onanimationend and onwebkitanimationend are not aliases]
expected: FAIL
- [dispatchEvent of a webkitAnimationEnd event does not trigger an unprefixed event handler or listener]
- expected: FAIL
-
[dispatchEvent of a webkitAnimationEnd event does trigger a prefixed event handler or listener]
expected: FAIL
[webkitAnimationEnd event listener should not trigger if an unprefixed listener also exists]
- expected: FAIL
+ expected: NOTRUN
[dispatchEvent of an animationend event does not trigger a prefixed event handler or listener]
expected: FAIL
[event types for prefixed and unprefixed animationend event listeners should be named appropriately]
- expected: FAIL
+ expected: NOTRUN
[onwebkitanimationend event handler should not trigger if an unprefixed event handler also exists]
expected: FAIL
diff --git a/tests/wpt/metadata/dom/events/webkit-transition-end-event.html.ini b/tests/wpt/metadata/dom/events/webkit-transition-end-event.html.ini
index 2e7d6443e31..4ee5fc21ce9 100644
--- a/tests/wpt/metadata/dom/events/webkit-transition-end-event.html.ini
+++ b/tests/wpt/metadata/dom/events/webkit-transition-end-event.html.ini
@@ -1,7 +1,4 @@
[webkit-transition-end-event.html]
- [dispatchEvent of a webkitTransitionEnd event does not trigger an unprefixed event handler or listener]
- expected: FAIL
-
[dispatchEvent of an transitionend event does not trigger a prefixed event handler or listener]
expected: FAIL
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index c4e49f39a76..6ad65fa2d0f 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -13870,7 +13870,7 @@
]
],
"interfaces.html": [
- "1a579837cc22d31a7792566615d9e321b3d7fe39",
+ "b6034be26af3c2edd1ef41703857fa99bd2cd639",
[
null,
{}
diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.html b/tests/wpt/mozilla/tests/mozilla/interfaces.html
index 1a579837cc2..b6034be26af 100644
--- a/tests/wpt/mozilla/tests/mozilla/interfaces.html
+++ b/tests/wpt/mozilla/tests/mozilla/interfaces.html
@@ -12,6 +12,7 @@
// IMPORTANT: Do not change the list below without review from a DOM peer!
test_interfaces([
"AnalyserNode",
+ "AnimationEvent",
"Attr",
"Audio",
"AudioBuffer",