diff options
author | Boris Chiou <boris.chiou@gmail.com> | 2017-04-24 13:22:25 +0800 |
---|---|---|
committer | Boris Chiou <boris.chiou@gmail.com> | 2017-04-26 21:35:05 +0800 |
commit | 02fc1789e8561dc9e9740a46e13ef8c9a360ee9c (patch) | |
tree | 192db897a1a5d0383a53239c71a3ca3d30aeded0 | |
parent | e5762cb6953b5e202e8733e39e8267c4b67a9622 (diff) | |
download | servo-02fc1789e8561dc9e9740a46e13ef8c9a360ee9c.tar.gz servo-02fc1789e8561dc9e9740a46e13ef8c9a360ee9c.zip |
Bug 1357357 - Make the parser of transition-property match the spec.
1. We add a new arm to TransitionProperty, TransitionProperty::Unsupported,
which contains an Atom, so it's better to remove the Copy trait from
TransitionProperty.
2. TransitionProperty::Unsupported(Atom) represents any non-animatable, custom,
or unrecognized property, and we use Atom to store the ident string for
serialization.
-rw-r--r-- | components/style/animation.rs | 18 | ||||
-rw-r--r-- | components/style/build_gecko.rs | 1 | ||||
-rw-r--r-- | components/style/dom.rs | 2 | ||||
-rw-r--r-- | components/style/gecko/wrapper.rs | 20 | ||||
-rw-r--r-- | components/style/gecko_bindings/bindings.rs | 6 | ||||
-rw-r--r-- | components/style/keyframes.rs | 2 | ||||
-rw-r--r-- | components/style/properties/gecko.mako.rs | 34 | ||||
-rw-r--r-- | components/style/properties/helpers/animated_properties.mako.rs | 49 | ||||
-rw-r--r-- | components/style/properties/properties.mako.rs | 4 | ||||
-rw-r--r-- | components/style/properties/shorthand/box.mako.rs | 4 | ||||
-rw-r--r-- | ports/geckolib/glue.rs | 6 | ||||
-rw-r--r-- | tests/unit/style/parsing/transition_property.rs | 40 | ||||
-rw-r--r-- | tests/wpt/metadata-css/css-transitions-1_dev/html/transition-property-002.htm.ini | 9 |
13 files changed, 139 insertions, 56 deletions
diff --git a/components/style/animation.rs b/components/style/animation.rs index 2229d485591..16c7dab364d 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -272,9 +272,13 @@ impl PropertyAnimation { let timing_function = box_style.transition_timing_function_mod(transition_index); let duration = box_style.transition_duration_mod(transition_index); + if let TransitionProperty::Unsupported(_) = transition_property { + return result + } + if transition_property.is_shorthand() { return transition_property.longhands().iter().filter_map(|transition_property| { - PropertyAnimation::from_transition_property(*transition_property, + PropertyAnimation::from_transition_property(transition_property, timing_function, duration, old_style, @@ -284,7 +288,7 @@ impl PropertyAnimation { if transition_property != TransitionProperty::All { if let Some(property_animation) = - PropertyAnimation::from_transition_property(transition_property, + PropertyAnimation::from_transition_property(&transition_property, timing_function, duration, old_style, @@ -296,7 +300,7 @@ impl PropertyAnimation { TransitionProperty::each(|transition_property| { if let Some(property_animation) = - PropertyAnimation::from_transition_property(transition_property, + PropertyAnimation::from_transition_property(&transition_property, timing_function, duration, old_style, @@ -308,15 +312,15 @@ impl PropertyAnimation { result } - fn from_transition_property(transition_property: TransitionProperty, + fn from_transition_property(transition_property: &TransitionProperty, timing_function: TransitionTimingFunction, duration: Time, old_style: &ComputedValues, new_style: &ComputedValues) -> Option<PropertyAnimation> { debug_assert!(!transition_property.is_shorthand() && - transition_property != TransitionProperty::All); - let animated_property = AnimatedProperty::from_transition_property(&transition_property, + transition_property != &TransitionProperty::All); + let animated_property = AnimatedProperty::from_transition_property(transition_property, old_style, new_style); @@ -702,7 +706,7 @@ pub fn update_style_for_animation(context: &SharedStyleContext, for transition_property in &animation.properties_changed { debug!("update_style_for_animation: scanning prop {:?} for animation \"{}\"", transition_property, name); - match PropertyAnimation::from_transition_property(*transition_property, + match PropertyAnimation::from_transition_property(transition_property, timing_function, Time::from_seconds(relative_duration as f32), &from_style, diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs index 00aac6d8526..9d170e64105 100644 --- a/components/style/build_gecko.rs +++ b/components/style/build_gecko.rs @@ -659,6 +659,7 @@ mod bindings { "StyleBasicShape", "StyleBasicShapeType", "StyleShapeSource", + "StyleTransition", "nsCSSFontFaceRule", "nsCSSKeyword", "nsCSSPropertyID", diff --git a/components/style/dom.rs b/components/style/dom.rs index ffc9f67ef8d..645db055be7 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -520,7 +520,7 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone + /// Returns true if we need to update transitions for the specified property on this element. #[cfg(feature = "gecko")] fn needs_transitions_update_per_property(&self, - property: TransitionProperty, + property: &TransitionProperty, combined_duration: f32, before_change_style: &Arc<ComputedValues>, after_change_style: &Arc<ComputedValues>, diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index 6c72aa0b3d5..948a87d4cf6 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -811,7 +811,7 @@ impl<'le> TElement for GeckoElement<'le> { continue; } - let mut property_check_helper = |property: TransitionProperty| -> bool { + let mut property_check_helper = |property: &TransitionProperty| -> bool { if self.needs_transitions_update_per_property(property, combined_duration, before_change_style, @@ -821,7 +821,9 @@ impl<'le> TElement for GeckoElement<'le> { } if let Some(set) = transitions_to_keep.as_mut() { - set.insert(property); + // The TransitionProperty here must be animatable, so cloning it is cheap + // because it is an integer-like enum. + set.insert(property.clone()); } false }; @@ -835,12 +837,12 @@ impl<'le> TElement for GeckoElement<'le> { }); if is_shorthand { let shorthand: TransitionProperty = property.into(); - if shorthand.longhands().iter().any(|&p| property_check_helper(p)) { + if shorthand.longhands().iter().any(|p| property_check_helper(p)) { return true; } } else { if animated_properties::nscsspropertyid_is_animatable(property) && - property_check_helper(property.into()) { + property_check_helper(&property.into()) { return true; } } @@ -855,7 +857,7 @@ impl<'le> TElement for GeckoElement<'le> { } fn needs_transitions_update_per_property(&self, - property: TransitionProperty, + property: &TransitionProperty, combined_duration: f32, before_change_style: &Arc<ComputedValues>, after_change_style: &Arc<ComputedValues>, @@ -869,17 +871,17 @@ impl<'le> TElement for GeckoElement<'le> { return false; } - if existing_transitions.contains_key(&property) { + if existing_transitions.contains_key(property) { // If there is an existing transition, update only if the end value differs. // If the end value has not changed, we should leave the currently running // transition as-is since we don't want to interrupt its timing function. let after_value = - Arc::new(AnimationValue::from_computed_values(&property, after_change_style)); - return existing_transitions.get(&property).unwrap() != &after_value; + Arc::new(AnimationValue::from_computed_values(property, after_change_style)); + return existing_transitions.get(property).unwrap() != &after_value; } combined_duration > 0.0f32 && - AnimatedProperty::from_transition_property(&property, + AnimatedProperty::from_transition_property(property, before_change_style, after_change_style).does_animate() } diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index c663df92012..f4d1a515d4b 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -39,6 +39,7 @@ use gecko_bindings::structs::SheetParsingMode; use gecko_bindings::structs::StyleBasicShape; use gecko_bindings::structs::StyleBasicShapeType; use gecko_bindings::structs::StyleShapeSource; +use gecko_bindings::structs::StyleTransition; use gecko_bindings::structs::nsCSSFontFaceRule; use gecko_bindings::structs::nsCSSKeyword; use gecko_bindings::structs::nsCSSPropertyID; @@ -693,6 +694,11 @@ extern "C" { -> RawServoAnimationValueBorrowedOrNull; } extern "C" { + pub fn Gecko_StyleTransition_SetUnsupportedProperty(aTransition: + *mut StyleTransition, + aAtom: *mut nsIAtom); +} +extern "C" { pub fn Gecko_Atomize(aString: *const ::std::os::raw::c_char, aLength: u32) -> *mut nsIAtom; } diff --git a/components/style/keyframes.rs b/components/style/keyframes.rs index d7e3485fc7d..fb8290fedf4 100644 --- a/components/style/keyframes.rs +++ b/components/style/keyframes.rs @@ -259,8 +259,8 @@ fn get_animated_properties(keyframes: &[Arc<Locked<Keyframe>>], guard: &SharedRw if let Some(property) = TransitionProperty::from_declaration(declaration) { if !seen.has_transition_property_bit(&property) { - ret.push(property); seen.set_transition_property_bit(&property); + ret.push(property); } } } diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 57ebd1114ff..fc40dcff52d 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -33,6 +33,7 @@ use gecko_bindings::bindings::Gecko_FontFamilyList_AppendNamed; use gecko_bindings::bindings::Gecko_FontFamilyList_Clear; use gecko_bindings::bindings::Gecko_SetCursorArrayLength; use gecko_bindings::bindings::Gecko_SetCursorImage; +use gecko_bindings::bindings::Gecko_StyleTransition_SetUnsupportedProperty; use gecko_bindings::bindings::Gecko_NewCSSShadowArray; use gecko_bindings::bindings::Gecko_nsStyleFont_SetLang; use gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom; @@ -53,6 +54,7 @@ use gecko::values::convert_rgba_to_nscolor; use gecko::values::GeckoStyleCoordConvertible; use gecko::values::round_border_to_device_pixels; use logical_geometry::WritingMode; +use properties::animated_properties::TransitionProperty; use properties::longhands; use properties::{Importance, LonghandId}; use properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyDeclarationId}; @@ -2149,7 +2151,12 @@ fn static_assert() { unsafe { self.gecko.mTransitions.ensure_len(v.0.len()) }; self.gecko.mTransitionPropertyCount = v.0.len() as u32; for (servo, gecko) in v.0.into_iter().zip(self.gecko.mTransitions.iter_mut()) { - gecko.mProperty = servo.into(); + match servo { + TransitionProperty::Unsupported(ref atom) => unsafe { + Gecko_StyleTransition_SetUnsupportedProperty(gecko, atom.as_ptr()) + }, + _ => gecko.mProperty = (&servo).into(), + } } } else { // In gecko |none| is represented by eCSSPropertyExtra_no_properties. @@ -2172,7 +2179,22 @@ fn static_assert() { pub fn transition_property_at(&self, index: usize) -> longhands::transition_property::computed_value::SingleComputedValue { - self.gecko.mTransitions[index].mProperty.into() + use gecko_bindings::structs::nsCSSPropertyID::eCSSPropertyExtra_no_properties; + use gecko_bindings::structs::nsCSSPropertyID::eCSSPropertyExtra_variable; + use gecko_bindings::structs::nsCSSPropertyID::eCSSProperty_UNKNOWN; + + let property = self.gecko.mTransitions[index].mProperty; + if property == eCSSProperty_UNKNOWN || property == eCSSPropertyExtra_variable { + let atom = self.gecko.mTransitions[index].mUnknownProperty.raw(); + debug_assert!(!atom.is_null()); + TransitionProperty::Unsupported(atom.into()) + } else if property == eCSSPropertyExtra_no_properties { + // Actually, we don't expect TransitionProperty::Unsupported also represents "none", + // but if the caller wants to convert it, it is fine. Please use it carefully. + TransitionProperty::Unsupported(atom!("none")) + } else { + property.into() + } } pub fn transition_nscsspropertyid_at(&self, index: usize) -> nsCSSPropertyID { @@ -2180,6 +2202,8 @@ fn static_assert() { } pub fn copy_transition_property_from(&mut self, other: &Self) { + use gecko_bindings::structs::nsCSSPropertyID::eCSSPropertyExtra_variable; + use gecko_bindings::structs::nsCSSPropertyID::eCSSProperty_UNKNOWN; unsafe { self.gecko.mTransitions.ensure_len(other.gecko.mTransitions.len()) }; let count = other.gecko.mTransitionPropertyCount; @@ -2187,6 +2211,12 @@ fn static_assert() { for (index, transition) in self.gecko.mTransitions.iter_mut().enumerate().take(count as usize) { transition.mProperty = other.gecko.mTransitions[index].mProperty; + if transition.mProperty == eCSSProperty_UNKNOWN || + transition.mProperty == eCSSPropertyExtra_variable { + let atom = other.gecko.mTransitions[index].mUnknownProperty.raw(); + debug_assert!(!atom.is_null()); + unsafe { Gecko_StyleTransition_SetUnsupportedProperty(transition, atom) }; + } } } ${impl_transition_count('property', 'Property')} diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 8783fc4a44f..cd384da294a 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -7,9 +7,10 @@ <% from data import SYSTEM_FONT_LONGHANDS %> use app_units::Au; -use cssparser::{Color as CSSParserColor, Parser, RGBA}; +use cssparser::{Color as CSSParserColor, Parser, RGBA, serialize_identifier}; use euclid::{Point2D, Size2D}; #[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSPropertyID; +#[cfg(feature = "gecko")] use gecko_string_cache::Atom; use properties::{CSSWideKeyword, PropertyDeclaration}; use properties::longhands; use properties::longhands::background_size::computed_value::T as BackgroundSizeList; @@ -25,6 +26,7 @@ use properties::longhands::transform::computed_value::T as TransformList; use properties::longhands::vertical_align::computed_value::T as VerticalAlign; use properties::longhands::visibility::computed_value::T as Visibility; #[cfg(feature = "gecko")] use properties::{PropertyDeclarationId, LonghandId}; +#[cfg(feature = "servo")] use servo_atoms::Atom; use std::cmp; #[cfg(feature = "gecko")] use std::collections::HashMap; use std::fmt; @@ -45,7 +47,7 @@ use values::generics::position as generic_position; /// property. // NB: This needs to be here because it needs all the longhands generated // beforehand. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum TransitionProperty { /// All, any animatable property changing should generate a transition. @@ -62,24 +64,27 @@ pub enum TransitionProperty { /// ${prop.name} ${prop.camel_case}, % endfor + /// Unrecognized property which could be any non-animatable, custom property, or + /// unknown property. + Unsupported(Atom) } impl TransitionProperty { /// Iterates over each longhand property. - pub fn each<F: FnMut(TransitionProperty) -> ()>(mut cb: F) { + pub fn each<F: FnMut(&TransitionProperty) -> ()>(mut cb: F) { % for prop in data.longhands: % if prop.animatable: - cb(TransitionProperty::${prop.camel_case}); + cb(&TransitionProperty::${prop.camel_case}); % endif % endfor } /// Iterates over every property that is not TransitionProperty::All, stopping and returning /// true when the provided callback returns true for the first time. - pub fn any<F: FnMut(TransitionProperty) -> bool>(mut cb: F) -> bool { + pub fn any<F: FnMut(&TransitionProperty) -> bool>(mut cb: F) -> bool { % for prop in data.longhands: % if prop.animatable: - if cb(TransitionProperty::${prop.camel_case}) { + if cb(&TransitionProperty::${prop.camel_case}) { return true; } % endif @@ -89,7 +94,8 @@ impl TransitionProperty { /// Parse a transition-property value. pub fn parse(input: &mut Parser) -> Result<Self, ()> { - match_ignore_ascii_case! { &try!(input.expect_ident()), + let ident = try!(input.expect_ident()); + match_ignore_ascii_case! { &ident, "all" => Ok(TransitionProperty::All), % for prop in data.longhands: % if prop.animatable: @@ -99,7 +105,13 @@ impl TransitionProperty { % for prop in data.shorthands_except_all(): "${prop.name}" => Ok(TransitionProperty::${prop.camel_case}), % endfor - _ => Err(()) + "none" => Err(()), + _ => { + match CSSWideKeyword::from_ident(&ident) { + Some(_) => Err(()), + None => Ok(TransitionProperty::Unsupported((&*ident).into())) + } + } } } @@ -199,6 +211,11 @@ impl ToCss for TransitionProperty { % for prop in data.shorthands_except_all(): TransitionProperty::${prop.camel_case} => dest.write_str("${prop.name}"), % endfor + #[cfg(feature = "gecko")] + TransitionProperty::Unsupported(ref atom) => serialize_identifier(&atom.to_string(), + dest), + #[cfg(feature = "servo")] + TransitionProperty::Unsupported(ref atom) => serialize_identifier(atom, dest), } } } @@ -206,9 +223,9 @@ impl ToCss for TransitionProperty { /// Convert to nsCSSPropertyID. #[cfg(feature = "gecko")] #[allow(non_upper_case_globals)] -impl From<TransitionProperty> for nsCSSPropertyID { - fn from(transition_property: TransitionProperty) -> nsCSSPropertyID { - match transition_property { +impl<'a> From< &'a TransitionProperty> for nsCSSPropertyID { + fn from(transition_property: &'a TransitionProperty) -> nsCSSPropertyID { + match *transition_property { % for prop in data.longhands: % if prop.animatable: TransitionProperty::${prop.camel_case} @@ -220,6 +237,7 @@ impl From<TransitionProperty> for nsCSSPropertyID { => ${helpers.to_nscsspropertyid(prop.ident)}, % endfor TransitionProperty::All => nsCSSPropertyID::eCSSPropertyExtra_all_properties, + _ => panic!("Unconvertable Servo transition property: {:?}", transition_property), } } } @@ -234,6 +252,9 @@ impl From<nsCSSPropertyID> for TransitionProperty { % if prop.animatable: ${helpers.to_nscsspropertyid(prop.ident)} => TransitionProperty::${prop.camel_case}, + % else: + ${helpers.to_nscsspropertyid(prop.ident)} + => TransitionProperty::Unsupported(Atom::from("${prop.ident}")), % endif % endfor % for prop in data.shorthands_except_all(): @@ -241,7 +262,7 @@ impl From<nsCSSPropertyID> for TransitionProperty { => TransitionProperty::${prop.camel_case}, % endfor nsCSSPropertyID::eCSSPropertyExtra_all_properties => TransitionProperty::All, - _ => panic!("Unsupported Servo transition property: {:?}", property), + _ => panic!("Unconvertable nsCSSPropertyID: {:?}", property), } } } @@ -356,7 +377,7 @@ impl AnimatedProperty { } % endif % endfor - other => panic!("Can't use TransitionProperty::{:?} here", other), + ref other => panic!("Can't use TransitionProperty::{:?} here", other), } } } @@ -544,7 +565,7 @@ impl AnimationValue { } % endif % endfor - other => panic!("Can't use TransitionProperty::{:?} here.", other), + ref other => panic!("Can't use TransitionProperty::{:?} here.", other), } } } diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 69932549fe2..fa6ed21a33b 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -258,7 +258,7 @@ impl LonghandIdSet { TransitionProperty::${prop.camel_case} => self.insert(LonghandId::${prop.camel_case}), % endif % endfor - other => unreachable!("Tried to set TransitionProperty::{:?} in a PropertyBitfield", other), + ref other => unreachable!("Tried to set TransitionProperty::{:?} in a PropertyBitfield", other), } } @@ -271,7 +271,7 @@ impl LonghandIdSet { TransitionProperty::${prop.camel_case} => self.contains(LonghandId::${prop.camel_case}), % endif % endfor - other => unreachable!("Tried to get TransitionProperty::{:?} in a PropertyBitfield", other), + ref other => unreachable!("Tried to get TransitionProperty::{:?} in a PropertyBitfield", other), } } } diff --git a/components/style/properties/shorthand/box.mako.rs b/components/style/properties/shorthand/box.mako.rs index cf98bffa347..0dd320735a8 100644 --- a/components/style/properties/shorthand/box.mako.rs +++ b/components/style/properties/shorthand/box.mako.rs @@ -98,10 +98,12 @@ macro_rules! try_parse_one { loop { parsed += 1; - try_parse_one!(input, property, transition_property); try_parse_one!(context, input, duration, transition_duration); try_parse_one!(context, input, timing_function, transition_timing_function); try_parse_one!(context, input, delay, transition_delay); + // Must check 'transition-property' after 'transition-timing-function' since + // 'transition-property' accepts any keyword. + try_parse_one!(input, property, transition_property); parsed -= 1; break diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 0366a05aa83..7e463db9d13 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -1985,7 +1985,7 @@ pub extern "C" fn Servo_GetComputedKeyframeValues(keyframes: RawGeckoKeyframeLis // This is safe since we immediately write to the uninitialized values. unsafe { animation_values.set_len((i + 1) as u32) }; seen.set_transition_property_bit(&anim.0); - animation_values[i].mProperty = anim.0.into(); + animation_values[i].mProperty = (&anim.0).into(); // We only make sure we have enough space for this variable, // but didn't construct a default value for StyleAnimationValue, // so we should zero it to avoid getting undefined behaviors. @@ -2056,7 +2056,7 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet let block = style.to_declaration_block(property.clone().into()); unsafe { (*keyframe).mPropertyValues.set_len((index + 1) as u32); - (*keyframe).mPropertyValues[index].mProperty = property.clone().into(); + (*keyframe).mPropertyValues[index].mProperty = property.into(); // FIXME. Do not set computed values once we handles missing keyframes // with additive composition. (*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky( @@ -2087,7 +2087,7 @@ pub extern "C" fn Servo_StyleSet_FillKeyframesForName(raw_data: RawServoStyleSet unsafe { let property = TransitionProperty::from_declaration(declaration).unwrap(); (*keyframe).mPropertyValues.set_len((index + 1) as u32); - (*keyframe).mPropertyValues[index].mProperty = property.into(); + (*keyframe).mPropertyValues[index].mProperty = (&property).into(); (*keyframe).mPropertyValues[index].mServoDeclarationBlock.set_arc_leaky( Arc::new(global_style_data.shared_lock.wrap( PropertyDeclarationBlock::with_one( diff --git a/tests/unit/style/parsing/transition_property.rs b/tests/unit/style/parsing/transition_property.rs index 5283f173afc..5929489651c 100644 --- a/tests/unit/style/parsing/transition_property.rs +++ b/tests/unit/style/parsing/transition_property.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use parsing::parse; +use servo_atoms::Atom; use style::properties::animated_properties::TransitionProperty; use style::properties::longhands::transition_property; use style::properties::shorthands::transition; @@ -13,16 +14,21 @@ fn test_longhand_properties() { assert_roundtrip_with_context!(transition_property::parse, "margin-left"); assert_roundtrip_with_context!(transition_property::parse, "background-color"); assert_roundtrip_with_context!(transition_property::parse, "width"); + assert_roundtrip_with_context!(transition_property::parse, "transition-duration"); + assert_roundtrip_with_context!(transition_property::parse, "unsupported-property"); + assert_roundtrip_with_context!(transition_property::parse, "-other-unsupported-property"); + assert_roundtrip_with_context!(transition_property::parse, "--var"); - assert_eq!(parse_longhand!(transition_property, "margin-left, width"), + assert_eq!(parse_longhand!(transition_property, "margin-left, transition-delay, width, --var"), transition_property::SpecifiedValue( vec![TransitionProperty::MarginLeft, - TransitionProperty::Width])); + TransitionProperty::Unsupported(Atom::from("transition-delay")), + TransitionProperty::Width, + TransitionProperty::Unsupported(Atom::from("--var"))])); - // TODO: If one of the identifiers listed is not a recognized property name or is not an - // animatable property, the implementation must still start transitions on the animatable - // properties. Therefore, the parser shouldn't return Err for non-animatable property. - assert!(parse(transition_property::parse, "transition-duration").is_err()); + assert!(parse(transition_property::parse, ".width").is_err()); + assert!(parse(transition_property::parse, "1width").is_err()); + assert!(parse(transition_property::parse, "- ").is_err()); } #[test] @@ -44,11 +50,22 @@ fn test_keywords() { assert_eq!(parse_longhand!(transition_property, "all"), transition_property::SpecifiedValue(vec![TransitionProperty::All])); + assert_eq!(parse_longhand!(transition_property, "width, all"), + transition_property::SpecifiedValue(vec![TransitionProperty::Width, + TransitionProperty::All])); + + // Using CSS Wide Keyword or none in the list will get the syntax invalid. + // Note: Only "none" alone is valid. + assert!(parse(transition_property::parse, "none").is_ok()); assert_eq!(parse_longhand!(transition_property, "none"), transition_property::SpecifiedValue(vec![])); - assert!(parse(transition_property::parse, "inherit").is_err()); assert!(parse(transition_property::parse, "initial").is_err()); + assert!(parse(transition_property::parse, "unset").is_err()); + assert!(parse(transition_property::parse, "width, none").is_err()); + assert!(parse(transition_property::parse, "width, initial").is_err()); + assert!(parse(transition_property::parse, "width, inherit").is_err()); + assert!(parse(transition_property::parse, "width, unset").is_err()); } #[test] @@ -61,7 +78,16 @@ fn test_transition_shorthand() { assert_eq!(result.transition_property, parse_longhand!(transition_property, "margin, all")); + let result = parse(transition::parse_value, "2s width, 3s --var, 4s background").unwrap(); + assert_eq!(result.transition_property, + parse_longhand!(transition_property, "width, --var, background")); + let result = parse(transition::parse_value, "none").unwrap(); assert_eq!(result.transition_property, parse_longhand!(transition_property, "none")); + + assert!(parse(transition::parse_value, "2s width, none").is_err()); + assert!(parse(transition::parse_value, "2s width, 2s initial").is_err()); + assert!(parse(transition::parse_value, "2s width, 3s unset").is_err()); + assert!(parse(transition::parse_value, "2s width, 4s inherit").is_err()); } diff --git a/tests/wpt/metadata-css/css-transitions-1_dev/html/transition-property-002.htm.ini b/tests/wpt/metadata-css/css-transitions-1_dev/html/transition-property-002.htm.ini index d32a55f8927..701a4cb902f 100644 --- a/tests/wpt/metadata-css/css-transitions-1_dev/html/transition-property-002.htm.ini +++ b/tests/wpt/metadata-css/css-transitions-1_dev/html/transition-property-002.htm.ini @@ -6,15 +6,6 @@ [parse 'all, none'] expected: FAIL - [parse 'foobar'] - expected: FAIL - - [parse 'all, foobar'] - expected: FAIL - - [parse 'foobar, all'] - expected: FAIL - [parse 'initial'] expected: FAIL |