mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 06:43:32 +00:00
Bug 1804574 - Part 1: Add auto to animation-duration longhand. r=firefox-style-system-reviewers,layout-reviewers,emilio
Also, in order to backwards-compatibility with Level 1, we have to serialize auto as 0s for getComputedStyle in some cases, which depend on the value of animation-timeline. Differential Revision: https://phabricator.services.mozilla.com/D217871
This commit is contained in:
parent
7aa1a52024
commit
b17423ff3b
@ -421,6 +421,7 @@ cbindgen-types = [
|
||||
{ gecko = "StyleAnimationFillMode", servo = "crate::values::computed::AnimationFillMode" },
|
||||
{ gecko = "StyleAnimationPlayState", servo = "crate::values::computed::AnimationPlayState" },
|
||||
{ gecko = "StyleAnimationComposition", servo = "crate::values::computed::AnimationComposition" },
|
||||
{ gecko = "StyleAnimationDuration", servo = "crate::values::computed::AnimationDuration" },
|
||||
{ gecko = "StyleTimelineName", servo = "crate::values::computed::TimelineName" },
|
||||
{ gecko = "StyleScrollAxis", servo = "crate::values::computed::ScrollAxis" },
|
||||
{ gecko = "StyleViewTimelineInset", servo = "crate::values::computed::ViewTimelineInset" },
|
||||
|
@ -300,8 +300,9 @@ static already_AddRefed<CSSAnimation> BuildAnimation(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const StyleAnimationDuration& duration = aStyle.GetAnimationDuration(animIdx);
|
||||
TimingParams timing = TimingParamsFromCSSParams(
|
||||
aStyle.GetAnimationDuration(animIdx).ToMilliseconds(),
|
||||
duration.IsAuto() ? 0.0f : duration.AsTime().ToMilliseconds(),
|
||||
aStyle.GetAnimationDelay(animIdx).ToMilliseconds(),
|
||||
aStyle.GetAnimationIterationCount(animIdx),
|
||||
aStyle.GetAnimationDirection(animIdx),
|
||||
|
@ -1132,7 +1132,7 @@ struct StyleAnimation {
|
||||
return mTimingFunction;
|
||||
}
|
||||
const StyleTime& GetDelay() const { return mDelay; }
|
||||
const StyleTime& GetDuration() const { return mDuration; }
|
||||
const StyleAnimationDuration& GetDuration() const { return mDuration; }
|
||||
nsAtom* GetName() const { return mName._0.AsAtom(); }
|
||||
StyleAnimationDirection GetDirection() const { return mDirection; }
|
||||
StyleAnimationFillMode GetFillMode() const { return mFillMode; }
|
||||
@ -1149,7 +1149,7 @@ struct StyleAnimation {
|
||||
private:
|
||||
StyleComputedTimingFunction mTimingFunction{
|
||||
StyleComputedTimingFunction::Keyword(StyleTimingKeyword::Ease)};
|
||||
StyleTime mDuration{0.0f};
|
||||
StyleAnimationDuration mDuration = StyleAnimationDuration::Auto();
|
||||
StyleTime mDelay{0.0f};
|
||||
StyleAnimationName mName;
|
||||
StyleAnimationDirection mDirection = StyleAnimationDirection::Normal;
|
||||
@ -1157,7 +1157,7 @@ struct StyleAnimation {
|
||||
StyleAnimationPlayState mPlayState = StyleAnimationPlayState::Running;
|
||||
StyleAnimationIterationCount mIterationCount{1.0f};
|
||||
StyleAnimationComposition mComposition = StyleAnimationComposition::Replace;
|
||||
StyleAnimationTimeline mTimeline{StyleAnimationTimeline::Auto()};
|
||||
StyleAnimationTimeline mTimeline = StyleAnimationTimeline::Auto();
|
||||
};
|
||||
|
||||
struct StyleScrollTimeline {
|
||||
@ -1665,7 +1665,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset {
|
||||
const mozilla::StyleTime& GetAnimationDelay(uint32_t aIndex) const {
|
||||
return mAnimations[aIndex % mAnimationDelayCount].GetDelay();
|
||||
}
|
||||
const mozilla::StyleTime& GetAnimationDuration(uint32_t aIndex) const {
|
||||
const mozilla::StyleAnimationDuration& GetAnimationDuration(
|
||||
uint32_t aIndex) const {
|
||||
return mAnimations[aIndex % mAnimationDurationCount].GetDuration();
|
||||
}
|
||||
mozilla::StyleAnimationDirection GetAnimationDirection(
|
||||
|
@ -13958,6 +13958,8 @@ if (IsCSSPropertyPrefEnabled("layout.css.scroll-driven-animations.enabled")) {
|
||||
gCSSProperties["-moz-animation"].subproperties.push("animation-timeline");
|
||||
gCSSProperties["-webkit-animation"].subproperties.push("animation-timeline");
|
||||
|
||||
gCSSProperties["animation-duration"].initial_values.push("auto");
|
||||
|
||||
gCSSProperties["animation-timeline"] = {
|
||||
domProp: "animationTimeline",
|
||||
inherited: false,
|
||||
|
@ -1452,6 +1452,12 @@ mask-mode mask-repeat mask-clip mask-origin mask-composite mask-position-x mask-
|
||||
self.mTransitionPropertyCount > 0
|
||||
}
|
||||
|
||||
/// Returns whether animation-timeline is initial value. We need this information to resolve
|
||||
/// animation-duration.
|
||||
pub fn has_initial_animation_timeline(&self) -> bool {
|
||||
self.mAnimationTimelineCount == 1 && self.animation_timeline_at(0).is_auto()
|
||||
}
|
||||
|
||||
pub fn animations_equals(&self, other: &Self) -> bool {
|
||||
return self.mAnimationNameCount == other.mAnimationNameCount
|
||||
&& self.mAnimationDelayCount == other.mAnimationDelayCount
|
||||
|
@ -224,16 +224,15 @@ ${helpers.predefined_type(
|
||||
|
||||
${helpers.predefined_type(
|
||||
"animation-duration",
|
||||
"Time",
|
||||
"computed::Time::zero()",
|
||||
"AnimationDuration",
|
||||
"computed::AnimationDuration::auto()",
|
||||
engines="gecko servo",
|
||||
initial_specified_value="specified::Time::zero()",
|
||||
parse_method="parse_non_negative",
|
||||
initial_specified_value="specified::AnimationDuration::auto()",
|
||||
vector=True,
|
||||
need_index=True,
|
||||
animation_type="none",
|
||||
extra_prefixes=animation_extra_prefixes,
|
||||
spec="https://drafts.csswg.org/css-transitions/#propdef-transition-duration",
|
||||
spec="https://drafts.csswg.org/css-animations-2/#animation-duration",
|
||||
affects="",
|
||||
)}
|
||||
|
||||
|
@ -1614,6 +1614,13 @@ pub mod style_structs {
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns whether animation-timeline is initial value. We need this information to
|
||||
/// resolve animation-duration.
|
||||
#[cfg(feature = "servo")]
|
||||
pub fn has_initial_animation_timeline(&self) -> bool {
|
||||
self.animation_timeline_count() == 1 && self.animation_timeline_at(0).is_auto()
|
||||
}
|
||||
|
||||
/// Returns whether there is any named progress timeline specified with
|
||||
/// scroll-timeline-name other than `none`.
|
||||
#[cfg(feature = "gecko")]
|
||||
|
@ -351,9 +351,11 @@ macro_rules! try_parse_one {
|
||||
//
|
||||
// https://drafts.csswg.org/css-animations-2/#animation-shorthand
|
||||
//
|
||||
// FIXME: Bug 1804574. The initial value of duration should be auto, per
|
||||
// css-animations-2.
|
||||
let has_duration = !self.animation_duration.0[i].is_zero();
|
||||
// Note: animation-timeline is not serialized for now because it is always the
|
||||
// initial value in this loop.
|
||||
let has_duration = !self.animation_duration.0[i].is_auto()
|
||||
&& (static_prefs::pref!("layout.css.scroll-driven-animations.enabled")
|
||||
|| !self.animation_duration.0[i].is_zero());
|
||||
let has_timing_function = !self.animation_timing_function.0[i].is_ease();
|
||||
let has_delay = !self.animation_delay.0[i].is_zero();
|
||||
let has_iteration_count = !self.animation_iteration_count.0[i].is_one();
|
||||
@ -368,7 +370,7 @@ macro_rules! try_parse_one {
|
||||
|
||||
let mut writer = SequenceWriter::new(dest, " ");
|
||||
|
||||
// To avoid ambiguity, we have to serialize duration if both duration is initial
|
||||
// To avoid ambiguity, we have to serialize duration if duration is initial
|
||||
// but delay is not. (In other words, it's ambiguous if we serialize delay only.)
|
||||
if has_duration || has_delay {
|
||||
writer.item(&self.animation_duration.0[i])?;
|
||||
|
@ -4,9 +4,10 @@
|
||||
|
||||
//! Computed values for properties related to animations and transitions
|
||||
|
||||
use crate::values::computed::{Context, LengthPercentage, ToComputedValue};
|
||||
use crate::values::computed::{Context, LengthPercentage, Time, ToComputedValue};
|
||||
use crate::values::generics::animation as generics;
|
||||
use crate::values::specified::animation as specified;
|
||||
use crate::values::CSSFloat;
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::{CssWriter, ToCss};
|
||||
|
||||
@ -15,6 +16,20 @@ pub use crate::values::specified::animation::{
|
||||
ScrollAxis, TimelineName, TransitionBehavior, TransitionProperty,
|
||||
};
|
||||
|
||||
/// A computed value for the `animation-duration` property.
|
||||
pub type AnimationDuration = generics::GenericAnimationDuration<Time>;
|
||||
|
||||
impl AnimationDuration {
|
||||
/// Returns the amount of seconds this time represents.
|
||||
#[inline]
|
||||
pub fn seconds(&self) -> CSSFloat {
|
||||
match *self {
|
||||
Self::Auto => 0.0,
|
||||
Self::Time(ref t) => t.seconds(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A computed value for the `animation-iteration-count` property.
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToResolvedValue, ToShmem)]
|
||||
#[repr(C)]
|
||||
|
@ -42,9 +42,9 @@ pub use self::align::{
|
||||
pub use self::align::{AlignSelf, JustifySelf};
|
||||
pub use self::angle::Angle;
|
||||
pub use self::animation::{
|
||||
AnimationComposition, AnimationDirection, AnimationFillMode, AnimationIterationCount,
|
||||
AnimationName, AnimationPlayState, AnimationTimeline, ScrollAxis, TimelineName,
|
||||
TransitionBehavior, TransitionProperty, ViewTimelineInset,
|
||||
AnimationComposition, AnimationDirection, AnimationDuration, AnimationFillMode,
|
||||
AnimationIterationCount, AnimationName, AnimationPlayState, AnimationTimeline, ScrollAxis,
|
||||
TimelineName, TransitionBehavior, TransitionProperty, ViewTimelineInset,
|
||||
};
|
||||
pub use self::background::{BackgroundRepeat, BackgroundSize};
|
||||
pub use self::basic_shape::FillRule;
|
||||
|
@ -5,6 +5,7 @@
|
||||
//! Computed time values.
|
||||
|
||||
use crate::values::CSSFloat;
|
||||
use crate::Zero;
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::{CssWriter, ToCss};
|
||||
|
||||
@ -22,11 +23,6 @@ impl Time {
|
||||
Time { seconds }
|
||||
}
|
||||
|
||||
/// Returns `0s`.
|
||||
pub fn zero() -> Self {
|
||||
Self::from_seconds(0.0)
|
||||
}
|
||||
|
||||
/// Returns the amount of seconds this time represents.
|
||||
#[inline]
|
||||
pub fn seconds(&self) -> CSSFloat {
|
||||
@ -43,3 +39,13 @@ impl ToCss for Time {
|
||||
dest.write_char('s')
|
||||
}
|
||||
}
|
||||
|
||||
impl Zero for Time {
|
||||
fn zero() -> Self {
|
||||
Self::from_seconds(0.0)
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.seconds == 0.
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,76 @@
|
||||
|
||||
use crate::values::generics::length::GenericLengthPercentageOrAuto;
|
||||
use crate::values::specified::animation::{ScrollAxis, ScrollFunction, TimelineName};
|
||||
use crate::Zero;
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::{CssWriter, ToCss};
|
||||
|
||||
/// The `animation-duration` property.
|
||||
///
|
||||
/// https://drafts.csswg.org/css-animations-2/#animation-duration
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
MallocSizeOf,
|
||||
PartialEq,
|
||||
SpecifiedValueInfo,
|
||||
ToComputedValue,
|
||||
ToShmem,
|
||||
)]
|
||||
#[repr(C, u8)]
|
||||
pub enum GenericAnimationDuration<T> {
|
||||
/// The initial value. However, we serialize this as 0s if the preference is disabled.
|
||||
Auto,
|
||||
/// The time value, <time [0s,∞]>.
|
||||
Time(T),
|
||||
}
|
||||
|
||||
pub use self::GenericAnimationDuration as AnimationDuration;
|
||||
|
||||
impl<T> AnimationDuration<T> {
|
||||
/// Returns the `auto` value.
|
||||
pub fn auto() -> Self {
|
||||
Self::Auto
|
||||
}
|
||||
|
||||
/// Returns true if it is `auto`.
|
||||
pub fn is_auto(&self) -> bool {
|
||||
matches!(*self, Self::Auto)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Zero> Zero for AnimationDuration<T> {
|
||||
fn zero() -> Self {
|
||||
Self::Time(T::zero())
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
match *self {
|
||||
Self::Time(ref t) => t.is_zero(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToCss + Zero> ToCss for AnimationDuration<T> {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
match *self {
|
||||
Self::Auto => {
|
||||
if static_prefs::pref!("layout.css.scroll-driven-animations.enabled") {
|
||||
dest.write_str("auto")
|
||||
} else {
|
||||
Self::Time(T::zero()).to_css(dest)
|
||||
}
|
||||
},
|
||||
Self::Time(ref t) => t.to_css(dest),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The view() notation.
|
||||
/// https://drafts.csswg.org/scroll-animations-1/#view-notation
|
||||
#[derive(
|
||||
|
33
servo/components/style/values/resolved/animation.rs
Normal file
33
servo/components/style/values/resolved/animation.rs
Normal file
@ -0,0 +1,33 @@
|
||||
/* 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/. */
|
||||
|
||||
//! Resolved animation values.
|
||||
|
||||
use super::{Context, ToResolvedValue};
|
||||
|
||||
use crate::values::computed::time::Time;
|
||||
use crate::values::computed::AnimationDuration;
|
||||
|
||||
impl ToResolvedValue for AnimationDuration {
|
||||
type ResolvedValue = Self;
|
||||
|
||||
fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
|
||||
match self {
|
||||
// For backwards-compatibility with Level 1, when the computed value of
|
||||
// animation-timeline is auto (i.e. only one list value, and that value being auto),
|
||||
// the resolved value of auto for animation-duration is 0s whenever its used value
|
||||
// would also be 0s.
|
||||
// https://drafts.csswg.org/css-animations-2/#animation-duration
|
||||
Self::Auto if context.style.get_ui().has_initial_animation_timeline() => {
|
||||
Self::Time(Time::from_seconds(0.0f32))
|
||||
},
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_resolved_value(value: Self::ResolvedValue) -> Self {
|
||||
value
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ use crate::ArcSlice;
|
||||
use servo_arc::Arc;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
mod animation;
|
||||
mod color;
|
||||
mod counters;
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::properties::{NonCustomPropertyId, PropertyId, ShorthandId};
|
||||
use crate::values::generics::animation as generics;
|
||||
use crate::values::specified::{LengthPercentage, NonNegativeNumber};
|
||||
use crate::values::specified::{LengthPercentage, NonNegativeNumber, Time};
|
||||
use crate::values::{CustomIdent, DashedIdent, KeyframesName};
|
||||
use crate::Atom;
|
||||
use cssparser::Parser;
|
||||
@ -150,6 +150,24 @@ impl TransitionBehavior {
|
||||
}
|
||||
}
|
||||
|
||||
/// A specified value for the `animation-duration` property.
|
||||
pub type AnimationDuration = generics::GenericAnimationDuration<Time>;
|
||||
|
||||
impl Parse for AnimationDuration {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if static_prefs::pref!("layout.css.scroll-driven-animations.enabled")
|
||||
&& input.try_parse(|i| i.expect_ident_matching("auto")).is_ok()
|
||||
{
|
||||
return Ok(Self::auto());
|
||||
}
|
||||
|
||||
Time::parse_non_negative(context, input).map(AnimationDuration::Time)
|
||||
}
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/css-animations/#animation-iteration-count
|
||||
#[derive(
|
||||
Copy, Clone, Debug, MallocSizeOf, PartialEq, Parse, SpecifiedValueInfo, ToCss, ToShmem,
|
||||
@ -568,7 +586,7 @@ impl Parse for TimelineName {
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(Self::none())
|
||||
return Ok(Self::none());
|
||||
}
|
||||
|
||||
DashedIdent::parse(context, input).map(TimelineName)
|
||||
@ -581,7 +599,7 @@ impl ToCss for TimelineName {
|
||||
W: Write,
|
||||
{
|
||||
if self.is_none() {
|
||||
return dest.write_str("none")
|
||||
return dest.write_str("none");
|
||||
}
|
||||
|
||||
self.0.to_css(dest)
|
||||
|
@ -29,9 +29,9 @@ pub use self::align::{AlignContent, AlignItems, AlignSelf, ContentDistribution};
|
||||
pub use self::align::{JustifyContent, JustifyItems, JustifySelf, SelfAlignment};
|
||||
pub use self::angle::{AllowUnitlessZeroAngle, Angle};
|
||||
pub use self::animation::{
|
||||
AnimationComposition, AnimationDirection, AnimationFillMode, AnimationIterationCount,
|
||||
AnimationName, AnimationPlayState, AnimationTimeline, ScrollAxis, TimelineName,
|
||||
TransitionBehavior, TransitionProperty, ViewTimelineInset,
|
||||
AnimationComposition, AnimationDirection, AnimationDuration, AnimationFillMode,
|
||||
AnimationIterationCount, AnimationName, AnimationPlayState, AnimationTimeline, ScrollAxis,
|
||||
TimelineName, TransitionBehavior, TransitionProperty, ViewTimelineInset,
|
||||
};
|
||||
pub use self::background::{BackgroundRepeat, BackgroundSize};
|
||||
pub use self::basic_shape::FillRule;
|
||||
|
@ -95,6 +95,7 @@ include = [
|
||||
"AnimationFillMode",
|
||||
"AnimationPlayState",
|
||||
"AnimationComposition",
|
||||
"AnimationDuration",
|
||||
"Appearance",
|
||||
"Au",
|
||||
"BreakBetween",
|
||||
|
@ -1,15 +1,3 @@
|
||||
[animation-duration-auto.tentative.html]
|
||||
[A value of auto can be specified for animation-duration]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['animation-duration'\] = "auto" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[Property animation-duration value 'auto']
|
||||
expected: FAIL
|
||||
|
||||
[e.style['animation'\] = "auto cubic-bezier(0, -2, 1, 3) -3s 4 reverse both paused anim" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[Property animation value 'auto cubic-bezier(0, -2, 1, 3) -3s 4 reverse both paused anim']
|
||||
expected: FAIL
|
||||
|
Loading…
Reference in New Issue
Block a user