From 8638c84fb540225da8e2808d06c99b20a520f6d3 Mon Sep 17 00:00:00 2001 From: Frederic Wang Date: Fri, 29 Sep 2023 09:00:46 +0000 Subject: [PATCH] Bug 1840478 - Handle inherits flag and initial value for custom properties. r=emilio,zrhoffman The CSS Properties and Values API allows to register CSS properties that can be either inherited or non-inherited, and which can also have initial values specified [1]. In [2], the representation of computed value for custom properties was changed to a pair of CustomPropertiesMaps: one map which is ref-counted (for properties unregistered or registered as inherited) and one which is not (for properties registered as non-inherited). The latter map is currently always None (i.e. all custom properties are handled as inherited) and several parts of the code assume this condition holds. This patch instead ensures that values for custom properties on a node are properly placed in the inherit or non_inherit map according to the inherits flag. Initial values for registered properties are taken into account and missing implementations of functions assuming non_inherited==None is completed. In order to minimize the size of the maps, absent values for non-inherited properties are interpreted as initial values during var substitution or retrieval of computed values (for non-inherited properties). This is used for `unset` and `initial` keywords while a copy of the parent's value is used for `inherit`. Last but not least, `CustomPropertiesBuilder` tries to perform lazy copy of the inherited style, postponing actual deep clone when necessary or falling back to a shallow copy when possible [3]. This is generalized a bit when the document contains custom properties registered as non-inherited and current optimizations are preserved as is for pages containing only non-registered custom properties. This could be further improved later [4]. [1] https://drafts.css-houdini.org/css-properties-values-api-1/ [2] https://hg.mozilla.org/mozilla-central/rev/8a7d9524a1b9 [3] https://bugzilla.mozilla.org/show_bug.cgi?id=1840478 [4] https://bugzilla.mozilla.org/show_bug.cgi?id=1855887 Differential Revision: https://phabricator.services.mozilla.com/D188812 --- layout/style/nsComputedDOMStyle.cpp | 3 +- servo/components/style/custom_properties.rs | 411 ++++++++++++++---- servo/components/style/properties/cascade.rs | 2 +- .../style/properties/declaration_block.rs | 2 +- .../style/properties/properties.mako.rs | 15 +- .../style/properties_and_values/registry.rs | 6 + servo/components/style/stylist.rs | 34 ++ servo/ports/geckolib/glue.rs | 55 ++- ...r-cssom-order-reverse-at-property.html.ini | 5 - .../layer-property-override.html.ini | 11 - .../animate-invalid.html.ini | 4 - ...operty-animation-angle-comma-list.html.ini | 3 - ...operty-animation-angle-space-list.html.ini | 3 - ...operty-animation-color-comma-list.html.ini | 3 - ...operty-animation-color-space-list.html.ini | 3 - ...m-property-animation-custom-ident.html.ini | 9 - .../custom-property-animation-image.html.ini | 9 - ...erty-animation-integer-comma-list.html.ini | 3 - ...erty-animation-integer-space-list.html.ini | 3 - ...perty-animation-length-comma-list.html.ini | 3 - ...tion-length-percentage-comma-list.html.ini | 3 - ...tion-length-percentage-space-list.html.ini | 3 - ...perty-animation-length-space-list.html.ini | 3 - ...perty-animation-number-comma-list.html.ini | 3 - ...perty-animation-number-space-list.html.ini | 3 - ...y-animation-percentage-comma-list.html.ini | 3 - ...y-animation-percentage-space-list.html.ini | 3 - ...y-animation-resolution-comma-list.html.ini | 3 - ...y-animation-resolution-space-list.html.ini | 3 - ...roperty-animation-time-comma-list.html.ini | 3 - ...roperty-animation-time-space-list.html.ini | 3 - .../custom-property-animation-url.html.ini | 9 - .../at-property-stylesheets.html.ini | 16 - .../at-property.html.ini | 57 --- .../determine-registration.html.ini | 28 -- ...registered-properties-inheritance.html.ini | 6 - ...istered-property-change-style-001.html.ini | 5 +- .../registered-property-crosstalk.html.ini | 3 - .../registered-property-cssom.html.ini | 3 - .../registered-property-initial.html.ini | 17 +- .../registered-property-revert.html.ini | 3 - .../self-utils.html.ini | 3 - ...ence-registered-properties-cycles.html.ini | 8 +- ...r-reference-registered-properties.html.ini | 21 + .../css-pseudo/highlight-cascade-004.html.ini | 2 - 45 files changed, 425 insertions(+), 376 deletions(-) delete mode 100644 testing/web-platform/meta/css/css-properties-values-api/animate-invalid.html.ini delete mode 100644 testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-custom-ident.html.ini delete mode 100644 testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-image.html.ini delete mode 100644 testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-url.html.ini delete mode 100644 testing/web-platform/meta/css/css-properties-values-api/at-property-stylesheets.html.ini delete mode 100644 testing/web-platform/meta/css/css-properties-values-api/registered-property-crosstalk.html.ini delete mode 100644 testing/web-platform/meta/css/css-properties-values-api/self-utils.html.ini delete mode 100644 testing/web-platform/meta/css/css-pseudo/highlight-cascade-004.html.ini diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 5b354a39b91d..936e25d3ff14 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -466,7 +466,8 @@ void nsComputedDOMStyle::GetPropertyValue( MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aMaybeCustomPropertyName)); const nsACString& name = Substring(aMaybeCustomPropertyName, CSS_CUSTOM_NAME_PREFIX_LENGTH); - Servo_GetCustomPropertyValue(mComputedStyle, &name, &aReturn); + Servo_GetCustomPropertyValue( + mComputedStyle, mPresShell->StyleSet()->RawData(), &name, &aReturn); return; } diff --git a/servo/components/style/custom_properties.rs b/servo/components/style/custom_properties.rs index 38ac6af583a9..48d1ef3d30b3 100644 --- a/servo/components/style/custom_properties.rs +++ b/servo/components/style/custom_properties.rs @@ -9,6 +9,7 @@ use crate::applicable_declarations::CascadePriority; use crate::media_queries::Device; use crate::properties::{CSSWideKeyword, CustomDeclaration, CustomDeclarationValue}; +use crate::properties_and_values::registry::PropertyRegistration; use crate::properties_and_values::value::ComputedValue as ComputedRegisteredValue; use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, PrecomputedHasher}; use crate::stylist::Stylist; @@ -207,13 +208,30 @@ impl ToCss for SpecifiedValue { pub type CustomPropertiesMap = IndexMap, BuildHasherDefault>; +// IndexMap equality doesn't consider ordering, which we have to account for. +// Also, for the same reason, IndexMap equality comparisons are slower than needed. +// +// See https://github.com/bluss/indexmap/issues/153 +fn maps_equal(l: Option<&CustomPropertiesMap>, r: Option<&CustomPropertiesMap>) -> bool { + match (l, r) { + (Some(l), Some(r)) => { + l.len() == r.len() && + l.iter() + .zip(r.iter()) + .all(|((k1, v1), (k2, v2))| k1 == k2 && v1 == v2) + }, + (None, None) => true, + _ => false, + } +} + /// A pair of separate CustomPropertiesMaps, split between custom properties /// that have the inherit flag set and those with the flag unset. #[repr(C)] #[derive(Clone, Debug, Default)] pub struct ComputedCustomProperties { - /// Map for custom properties with inherit flag set, including classical CSS - /// variables. Defined as ref-counted for cheap copy. + /// Map for custom properties with inherit flag set, including non-registered + /// ones. Defined as ref-counted for cheap copy. pub inherited: Option>, /// Map for custom properties with inherit flag unset. pub non_inherited: Option>, @@ -225,31 +243,47 @@ impl ComputedCustomProperties { self.inherited.is_none() && self.non_inherited.is_none() } + /// Return the name and value of the property at specified index, if any. + pub fn property_at(&self, index: usize) -> Option<(&Name, &Arc)> { + // Just expose the custom property items from + // custom_properties.inherited, followed by custom property items from + // custom_properties.non_inherited. + // TODO(bug 1855629): We should probably expose all properties that + // don't have the guaranteed-invalid-value (including non-inherited + // properties with an initial value), not just the ones in the maps. + // TODO(bug 1855629): In which order should we expose these properties? + match (&self.inherited, &self.non_inherited) { + (Some(p1), Some(p2)) => p1 + .get_index(index) + .or_else(|| p2.get_index(index - p1.len())), + (Some(p1), None) => p1.get_index(index), + (None, Some(p2)) => p2.get_index(index), + (None, None) => None, + } + } + fn read(&self) -> ReadOnlyCustomProperties { ReadOnlyCustomProperties { inherited: self.inherited.as_deref(), non_inherited: self.non_inherited.as_deref(), } } + + fn inherited_equal(&self, other: &Self) -> bool { + maps_equal(self.inherited.as_deref(), other.inherited.as_deref()) + } + + fn non_inherited_equal(&self, other: &Self) -> bool { + maps_equal( + self.non_inherited.as_deref(), + other.non_inherited.as_deref(), + ) + } } impl PartialEq for ComputedCustomProperties { fn eq(&self, other: &Self) -> bool { - // IndexMap equality doesn't consider ordering, which we have to account for. - // Also, for the same reason, IndexMap equality comparisons are slower than needed. - // - // See https://github.com/bluss/indexmap/issues/153 - // TODO(bug 1840478): Handle non-inherited properties. - match (&self.inherited, &other.inherited) { - (Some(l), Some(r)) => { - l.len() == r.len() && - l.iter() - .zip(r.iter()) - .all(|((k1, v1), (k2, v2))| k1 == k2 && v1 == v2) - }, - (None, None) => true, - _ => false, - } + self.inherited_equal(other) && self.non_inherited_equal(other) } } @@ -265,31 +299,44 @@ impl MutableCustomProperties { /// map, depending on whether the inherit flag is set or unset. fn insert( &mut self, + registration: Option<&PropertyRegistration>, name: Name, value: Arc, ) -> Option> { - // TODO(bug 1840478): Handle non-inherited properties. - let map = self - .inherited - .get_or_insert_with(|| UniqueArc::new(CustomPropertiesMap::default())); - map.insert(name, value) + self.get_map(registration).insert(name, value) } /// Remove a custom property from the corresponding inherited/non_inherited /// map, depending on whether the inherit flag is set or unset. - fn remove(&mut self, name: &Name) -> Option> { - // TODO(bug 1840478): Handle non-inherited properties. - self.inherited.as_mut()?.remove(name) + fn remove( + &mut self, + registration: Option<&PropertyRegistration>, + name: &Name, + ) -> Option> { + self.get_map(registration).remove(name) } - /// Shrink the capacity of the inherited/non_inherited maps as much as - /// possible. - fn shrink_to_fit(&mut self) { + /// Shrink the capacity of the inherited map as much as possible. An empty + /// map is just replaced with None. + fn inherited_shrink_to_fit(&mut self) { if let Some(ref mut map) = self.inherited { - map.shrink_to_fit(); + if map.is_empty() { + self.inherited = None; + } else { + map.shrink_to_fit(); + } } + } + + /// Shrink the capacity of the non_inherited map as much as possible. An + /// empty map is just replaced with None. + fn non_inherited_shrink_to_fit(&mut self) { if let Some(ref mut map) = self.non_inherited { - map.shrink_to_fit(); + if map.is_empty() { + self.non_inherited = None; + } else { + map.shrink_to_fit(); + } } } @@ -299,6 +346,16 @@ impl MutableCustomProperties { non_inherited: self.non_inherited.as_deref(), } } + + fn get_map(&mut self, registration: Option<&PropertyRegistration>) -> &mut CustomPropertiesMap { + if registration.map_or(true, |r| r.inherits) { + self.inherited + .get_or_insert_with(|| UniqueArc::new(Default::default())) + } else { + self.non_inherited + .get_or_insert_with(|| Box::new(Default::default())) + } + } } #[derive(Copy, Clone, Default)] @@ -308,9 +365,13 @@ struct ReadOnlyCustomProperties<'a> { } impl<'a> ReadOnlyCustomProperties<'a> { - fn get(&self, name: &Name) -> Option<&Arc> { - // TODO(bug 1840478): Handle non-inherited properties. - self.inherited?.get(name) + fn get(&self, stylist: &Stylist, name: &Name) -> Option<&Arc> { + let registration = stylist.get_custom_property_registration(&name); + if registration.map_or(true, |r| r.inherits) { + self.inherited?.get(name) + } else { + self.non_inherited?.get(name) + } } } @@ -697,7 +758,6 @@ fn parse_and_substitute_fallback<'i>( custom_properties: ReadOnlyCustomProperties, stylist: &Stylist, ) -> Result> { - debug_assert!(custom_properties.non_inherited.is_none()); input.skip_whitespace(); let after_comma = input.state(); let first_token_type = input @@ -766,12 +826,29 @@ pub struct CustomPropertiesBuilder<'a> { impl<'a> CustomPropertiesBuilder<'a> { /// Create a new builder, inheriting from a given custom properties map. - pub fn new(inherited: &'a ComputedCustomProperties, stylist: &'a Stylist) -> Self { + pub fn new( + inherited: &'a ComputedCustomProperties, + stylist: &'a Stylist, + is_root_element: bool, + ) -> Self { Self { seen: PrecomputedHashSet::default(), reverted: Default::default(), may_have_cycles: false, - custom_properties: MutableCustomProperties::default(), + custom_properties: MutableCustomProperties { + inherited: if is_root_element { + debug_assert!(inherited.is_empty()); + stylist + .get_custom_property_initial_values() + .map(UniqueArc::new) + } else { + // This should just be a copy of inherited.inherited, but + // do it lazily and postpone that to when that actually + // becomes necessary in the cascade and build methods. + None + }, + non_inherited: None, + }, inherited, stylist, } @@ -799,15 +876,16 @@ impl<'a> CustomPropertiesBuilder<'a> { return; } - // TODO(bug 1840478): Handle non-inherited properties. + // TODO(bug 1855887): Try to postpone cloning of inherited.inherited. if self.custom_properties.inherited.is_none() { - self.custom_properties.inherited = Some(match &self.inherited.inherited { - Some(inherited) => UniqueArc::new((**inherited).clone()), - None => UniqueArc::new(CustomPropertiesMap::default()), - }); + self.custom_properties.inherited = self + .inherited + .inherited + .as_ref() + .map(|i| UniqueArc::new((**i).clone())); } - let map = &mut self.custom_properties; + let custom_registration = self.stylist.get_custom_property_registration(&name); match *value { CustomDeclarationValue::Value(ref unparsed_value) => { let has_custom_property_references = @@ -828,17 +906,20 @@ impl<'a> CustomPropertiesBuilder<'a> { ); return; } - if let Some(registration) = self.stylist.get_custom_property_registration(&name) - { + if let Some(registration) = custom_registration { let mut input = ParserInput::new(&unparsed_value.css); let mut input = Parser::new(&mut input); if ComputedRegisteredValue::compute(&mut input, registration).is_err() { - map.remove(name); + map.remove(custom_registration, name); return; } } } - map.insert(name.clone(), Arc::clone(unparsed_value)); + map.insert( + custom_registration, + name.clone(), + Arc::clone(unparsed_value), + ); }, CustomDeclarationValue::CSSWideKeyword(keyword) => match keyword { CSSWideKeyword::RevertLayer | CSSWideKeyword::Revert => { @@ -847,43 +928,130 @@ impl<'a> CustomPropertiesBuilder<'a> { self.reverted.insert(name, (priority, origin_revert)); }, CSSWideKeyword::Initial => { - map.remove(name); + // For non-inherited custom properties, 'initial' was handled in value_may_affect_style. + debug_assert!( + custom_registration.map_or(true, |r| r.inherits), + "Should've been handled earlier" + ); + map.remove(custom_registration, name); + if let Some(registration) = custom_registration { + if let Some(ref initial_value) = registration.initial_value { + map.insert(custom_registration, name.clone(), initial_value.clone()); + } + } + }, + CSSWideKeyword::Inherit => { + // For inherited custom properties, 'inherit' was handled in value_may_affect_style. + debug_assert!( + !custom_registration.map_or(true, |r| r.inherits), + "Should've been handled earlier" + ); + if let Some(inherited_value) = self + .inherited + .non_inherited + .as_ref() + .and_then(|m| m.get(name)) + { + map.insert(custom_registration, name.clone(), inherited_value.clone()); + } }, // handled in value_may_affect_style - CSSWideKeyword::Unset | CSSWideKeyword::Inherit => unreachable!(), + CSSWideKeyword::Unset => unreachable!(), }, } } fn value_may_affect_style(&self, name: &Name, value: &CustomDeclarationValue) -> bool { + let custom_registration = self.stylist.get_custom_property_registration(&name); match *value { - CustomDeclarationValue::CSSWideKeyword(CSSWideKeyword::Unset) | CustomDeclarationValue::CSSWideKeyword(CSSWideKeyword::Inherit) => { - // Custom properties are inherited by default. So - // explicit 'inherit' or 'unset' means we can just use - // any existing value in the inherited CustomPropertiesMap. + // For inherited custom properties, explicit 'inherit' means we + // can just use any existing value in the inherited + // CustomPropertiesMap. + if custom_registration.map_or(true, |r| r.inherits) { + return false; + } + }, + CustomDeclarationValue::CSSWideKeyword(CSSWideKeyword::Initial) => { + // For non-inherited custom properties, explicit 'initial' means + // we can just use any initial value in the registration. + if !custom_registration.map_or(true, |r| r.inherits) { + return false; + } + }, + CustomDeclarationValue::CSSWideKeyword(CSSWideKeyword::Unset) => { + // Explicit 'unset' means we can either just use any existing + // value in the inherited CustomPropertiesMap or the initial + // value in the registration. return false; }, _ => {}, } - // TODO(bug 1840478): Handle non-inherited properties. - let existing_value = self - .custom_properties - .inherited - .as_ref() - .and_then(|m| m.get(name)) - .or_else(|| self.inherited.inherited.as_ref().and_then(|m| m.get(name))); + let existing_value = if custom_registration.map_or(true, |r| r.inherits) { + self.custom_properties + .inherited + .as_ref() + .and_then(|m| m.get(name)) + .or_else(|| self.inherited.inherited.as_ref().and_then(|m| m.get(name))) + } else { + debug_assert!(self + .custom_properties + .non_inherited + .as_ref() + .map_or(true, |m| !m.contains_key(name))); + custom_registration.and_then(|m| m.initial_value.as_ref()) + }; match (existing_value, value) { (None, &CustomDeclarationValue::CSSWideKeyword(CSSWideKeyword::Initial)) => { - // The initial value of a custom property is the same as it + debug_assert!( + custom_registration.map_or(true, |r| r.inherits), + "Should've been handled earlier" + ); + // The initial value of a custom property without a + // guaranteed-invalid initial value is the same as it // not existing in the map. - return false; + if custom_registration.map_or(true, |r| r.initial_value.is_none()) { + return false; + } + }, + ( + Some(existing_value), + &CustomDeclarationValue::CSSWideKeyword(CSSWideKeyword::Initial), + ) => { + debug_assert!( + custom_registration.map_or(true, |r| r.inherits), + "Should've been handled earlier" + ); + // Don't bother overwriting an existing value with the initial + // value specified in the registration. + if let Some(registration) = custom_registration { + if Some(existing_value) == registration.initial_value.as_ref() { + return false; + } + } + }, + (Some(_), &CustomDeclarationValue::CSSWideKeyword(CSSWideKeyword::Inherit)) => { + debug_assert!( + !custom_registration.map_or(true, |r| r.inherits), + "Should've been handled earlier" + ); + // existing_value is the registered initial value. + // Don't bother adding it to self.custom_properties.non_inherited + // if the key is also absent from self.inherited.non_inherited. + if self + .inherited + .non_inherited + .as_ref() + .map_or(true, |m| !m.contains_key(name)) + { + return false; + } }, (Some(existing_value), &CustomDeclarationValue::Value(ref value)) => { - // Don't bother overwriting an existing inherited value with - // the same specified value. + // Don't bother overwriting an existing value with the same + // specified value. if existing_value == value { return false; } @@ -895,16 +1063,18 @@ impl<'a> CustomPropertiesBuilder<'a> { } fn inherited_properties_match(&self, custom_properties: &MutableCustomProperties) -> bool { - // TODO(bug 1840478): Handle non-inherited properties. let (inherited, map) = match (&self.inherited.inherited, &custom_properties.inherited) { (Some(inherited), Some(map)) => (inherited, map), - (None, None) => return true, + (_, None) => return true, _ => return false, }; if inherited.len() != map.len() { return false; } for name in self.seen.iter() { + // IndexMap.get() returns None if the element is not in the map, so + // we don't bother checking whether name actually corresponds to an + // inherited custom property here. if inherited.get(*name) != map.get(*name) { return false; } @@ -914,19 +1084,36 @@ impl<'a> CustomPropertiesBuilder<'a> { /// Returns the final map of applicable custom properties. /// - /// If there was any specified property, we've created a new map and now we + /// If there was any specified property or non-inherited custom property + /// with an initial value, we've created a new map and now we /// need to remove any potential cycles, and wrap it in an arc. /// /// Otherwise, just use the inherited custom properties map. pub fn build(mut self) -> ComputedCustomProperties { - // TODO(bug 1840478): Handle non-inherited properties. - debug_assert!(self.custom_properties.non_inherited.is_none()); - debug_assert!(self.inherited.non_inherited.is_none()); if self.custom_properties.inherited.is_none() { - return self.inherited.clone(); + // Return early when self.custom_properties is empty, covering the + // common case of nodes without any custom property specified. In + // that situation, inherited properties will just use the value from + // self.inherited while non-inherited properties will use their + // initial values. These initial values are required to be + // 'computationally independent' but may still differ from the ones + // in self.inherited, so ensure they are used in the parent too. + if self.custom_properties.non_inherited.is_none() && + self.inherited.non_inherited.is_none() + { + return self.inherited.clone(); + } } if self.may_have_cycles { + // TODO(bug 1855887): Try to postpone cloning of inherited.inherited. + if self.custom_properties.inherited.is_none() { + self.custom_properties.inherited = self + .inherited + .inherited + .as_ref() + .map(|i| UniqueArc::new((**i).clone())); + } substitute_all( &mut self.custom_properties, self.inherited, @@ -940,10 +1127,15 @@ impl<'a> CustomPropertiesBuilder<'a> { // haven't really changed, and save some memory by reusing the inherited // map in that case. if self.inherited_properties_match(&self.custom_properties) { - return self.inherited.clone(); + self.custom_properties.non_inherited_shrink_to_fit(); + return ComputedCustomProperties { + inherited: self.inherited.inherited.clone(), + non_inherited: self.custom_properties.non_inherited.take(), + }; } - self.custom_properties.shrink_to_fit(); + self.custom_properties.inherited_shrink_to_fit(); + self.custom_properties.non_inherited_shrink_to_fit(); ComputedCustomProperties { inherited: self .custom_properties @@ -1028,7 +1220,7 @@ fn substitute_all( // Some shortcut checks. let (name, value) = { let props = context.map.read(); - let value = props.get(name)?; + let value = props.get(context.stylist, name)?; // Nothing to resolve. if value.references.custom_properties.is_empty() { @@ -1127,12 +1319,18 @@ fn substitute_all( // Anything here is in a loop which can traverse to the // variable we are handling, so remove it from the map, it's invalid // at computed-value time. - context.map.remove(&var_name); + context.map.remove( + context.stylist.get_custom_property_registration(&var_name), + &var_name, + ); in_loop = true; } if in_loop { // This variable is in loop. Resolve to invalid. - context.map.remove(&name); + context.map.remove( + context.stylist.get_custom_property_registration(&name), + &name, + ); return None; } @@ -1177,6 +1375,7 @@ fn substitute_references_in_value_and_apply( ) { debug_assert!(value.has_references()); + let custom_registration = stylist.get_custom_property_registration(&name); let mut computed_value = ComputedValue::empty(); { @@ -1196,7 +1395,7 @@ fn substitute_references_in_value_and_apply( Ok(t) => t, Err(..) => { // Invalid at computed value time. - custom_properties.remove(name); + custom_properties.remove(custom_registration, name); return; }, }; @@ -1205,7 +1404,7 @@ fn substitute_references_in_value_and_apply( .push_from(&input, position, last_token_type) .is_err() { - custom_properties.remove(name); + custom_properties.remove(custom_registration, name); return; } } @@ -1215,34 +1414,53 @@ fn substitute_references_in_value_and_apply( let mut input = Parser::new(&mut input); // If variable fallback results in a wide keyword, deal with it now. + let inherits = custom_registration.map_or(true, |r| r.inherits); + if let Ok(kw) = input.try_parse(CSSWideKeyword::parse) { - match kw { - CSSWideKeyword::Initial => { - custom_properties.remove(name); + match (kw, inherits) { + (CSSWideKeyword::Initial, _) | + (CSSWideKeyword::Revert, false) | + (CSSWideKeyword::RevertLayer, false) | + (CSSWideKeyword::Unset, false) => { + // TODO(bug 1273706): Do we really need to insert the initial value if inherits==false? + custom_properties.remove(custom_registration, name); + if let Some(registration) = custom_registration { + if let Some(ref initial_value) = registration.initial_value { + custom_properties.insert( + custom_registration, + name.clone(), + Arc::clone(initial_value), + ); + } + } }, - CSSWideKeyword::Revert | - CSSWideKeyword::RevertLayer | - CSSWideKeyword::Inherit | - CSSWideKeyword::Unset => { + (CSSWideKeyword::Revert, true) | + (CSSWideKeyword::RevertLayer, true) | + (CSSWideKeyword::Inherit, _) | + (CSSWideKeyword::Unset, true) => { + // TODO(bug 1273706): Do we really need to insert the inherited value if inherits==true? // TODO: It's unclear what this should do for revert / revert-layer, see // https://github.com/w3c/csswg-drafts/issues/9131. For now treating as unset // seems fine? - // TODO(bug 1840478): Handle non-inherited properties. - match inherited.inherited.as_ref().and_then(|map| map.get(name)) { + match inherited.read().get(stylist, name) { Some(value) => { - custom_properties.insert(name.clone(), Arc::clone(value)); + custom_properties.insert( + custom_registration, + name.clone(), + Arc::clone(value), + ); }, None => { - custom_properties.remove(name); + custom_properties.remove(custom_registration, name); }, }; }, } false } else { - if let Some(registration) = stylist.get_custom_property_registration(&name) { + if let Some(registration) = custom_registration { if ComputedRegisteredValue::compute(&mut input, registration).is_err() { - custom_properties.remove(name); + custom_properties.remove(custom_registration, name); return; } } @@ -1251,7 +1469,7 @@ fn substitute_references_in_value_and_apply( }; if should_insert { computed_value.css.shrink_to_fit(); - custom_properties.insert(name.clone(), Arc::new(computed_value)); + custom_properties.insert(custom_registration, name.clone(), Arc::new(computed_value)); } } @@ -1272,7 +1490,6 @@ fn substitute_block<'i>( custom_properties: ReadOnlyCustomProperties, stylist: &Stylist, ) -> Result> { - debug_assert!(custom_properties.non_inherited.is_none()); let mut last_token_type = TokenSerializationType::nothing(); let mut set_position_at_next_iteration = false; loop { @@ -1328,9 +1545,15 @@ fn substitute_block<'i>( None } } else { - // TODO(bug 1840478): Handle non-inherited properties. registration = stylist.get_custom_property_registration(&name); - custom_properties.get(&name).map(|v| &**v) + let value = custom_properties.get(stylist, &name); + if registration.map_or(true, |r| r.inherits) { + value.map(|v| &**v) + } else { + value + .or_else(|| registration.and_then(|m| m.initial_value.as_ref())) + .map(|v| &**v) + } }; if let Some(v) = value { diff --git a/servo/components/style/properties/cascade.rs b/servo/components/style/properties/cascade.rs index fec1e9b60908..e6deac97ce5e 100644 --- a/servo/components/style/properties/cascade.rs +++ b/servo/components/style/properties/cascade.rs @@ -290,7 +290,7 @@ where { let mut builder = - CustomPropertiesBuilder::new(inherited_style.custom_properties(), stylist); + CustomPropertiesBuilder::new(inherited_style.custom_properties(), stylist, is_root_element); for (declaration, priority) in iter { if let PropertyDeclaration::Custom(ref declaration) = *declaration { builder.cascade(declaration, priority); diff --git a/servo/components/style/properties/declaration_block.rs b/servo/components/style/properties/declaration_block.rs index 9dc0a2a42f2f..60a10e1e974c 100644 --- a/servo/components/style/properties/declaration_block.rs +++ b/servo/components/style/properties/declaration_block.rs @@ -946,7 +946,7 @@ impl PropertyDeclarationBlock { inherited_custom_properties: &crate::custom_properties::ComputedCustomProperties, stylist: &Stylist, ) -> crate::custom_properties::ComputedCustomProperties { - let mut builder = CustomPropertiesBuilder::new(inherited_custom_properties, stylist); + let mut builder = CustomPropertiesBuilder::new(inherited_custom_properties, stylist, false); for declaration in self.normal_declaration_iter() { if let PropertyDeclaration::Custom(ref declaration) = *declaration { diff --git a/servo/components/style/properties/properties.mako.rs b/servo/components/style/properties/properties.mako.rs index 9e6f5abcb0c3..046ec4406d45 100644 --- a/servo/components/style/properties/properties.mako.rs +++ b/servo/components/style/properties/properties.mako.rs @@ -3258,11 +3258,18 @@ impl ComputedValues { s } PropertyDeclarationId::Custom(name) => { - // TODO(bug 1840478): Handle non-inherited properties. - self.custom_properties - .as_ref().inherited.unwrap() + // FIXME(bug 1273706): This should use a stylist to determine + // whether the name corresponds to an inherited custom property + // and then choose the inherited/non_inherited map accordingly. + // It should also fallback to registered initial values for + // non-inherited properties. See Servo_GetCustomPropertyValue. + let p = &self.custom_properties; + let value = p + .inherited + .as_ref() .and_then(|map| map.get(name)) - .map_or(String::new(), |value| value.to_css_string()) + .or_else(|| p.non_inherited.as_ref().and_then(|map| map.get(name))); + value.map_or(String::new(), |value| value.to_css_string()) } } } diff --git a/servo/components/style/properties_and_values/registry.rs b/servo/components/style/properties_and_values/registry.rs index 3dee8cc64002..aed2df0d43f1 100644 --- a/servo/components/style/properties_and_values/registry.rs +++ b/servo/components/style/properties_and_values/registry.rs @@ -39,6 +39,12 @@ impl ScriptRegistry { self.properties.get(name) } + /// Gets already-registered custom properties via script. + #[inline] + pub fn properties(&self) -> &PrecomputedHashMap { + &self.properties + } + /// Register a given property. As per /// /// we don't allow overriding the registration. diff --git a/servo/components/style/stylist.rs b/servo/components/style/stylist.rs index 2b365bfbf6a5..66d69608c0bd 100644 --- a/servo/components/style/stylist.rs +++ b/servo/components/style/stylist.rs @@ -8,6 +8,7 @@ use crate::applicable_declarations::{ ApplicableDeclarationBlock, ApplicableDeclarationList, CascadePriority, }; use crate::context::{CascadeInputs, QuirksMode}; +use crate::custom_properties::CustomPropertiesMap; use crate::dom::TElement; #[cfg(feature = "gecko")] use crate::gecko_bindings::structs::{ServoStyleSetSizes, StyleRuleInclusion}; @@ -695,6 +696,39 @@ impl Stylist { None } + /// Returns a map of initial values for registered properties with the + /// inherits flag set and a specified initial value. + /// https://drafts.css-houdini.org/css-properties-values-api-1/#determining-registration + pub fn get_custom_property_initial_values(&self) -> Option { + let mut seen_names = PrecomputedHashSet::default(); + let mut map = CustomPropertiesMap::default(); + for (k, v) in self.custom_property_script_registry().properties().iter() { + seen_names.insert(k.clone()); + if v.inherits { + if let Some(value) = &v.initial_value { + map.insert(k.clone(), value.clone()); + } + } + } + for (data, _) in self.iter_origins() { + for (k, v) in data.custom_property_registrations.iter() { + if seen_names.insert(k.clone()) { + let last_value = &v.last().unwrap().0; + if last_value.inherits { + if let Some(ref value) = last_value.initial_value { + map.insert(k.clone(), value.clone()); + } + } + } + } + } + if map.is_empty() { + None + } else { + map.shrink_to_fit(); + Some(map) + } + } /// Rebuilds (if needed) the CascadeData given a sheet collection. pub fn rebuild_author_data( diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs index 4747e0f1352d..560739efb092 100644 --- a/servo/ports/geckolib/glue.rs +++ b/servo/ports/geckolib/glue.rs @@ -7420,32 +7420,39 @@ pub unsafe extern "C" fn Servo_GetResolvedValue( #[no_mangle] pub unsafe extern "C" fn Servo_GetCustomPropertyValue( computed_values: &ComputedValues, + raw_style_set: &PerDocumentStyleData, name: &nsACString, value: &mut nsACString, ) -> bool { - // TODO(bug 1840478): Handle non-inherited properties. - let inherited = match &computed_values.custom_properties.inherited { - Some(p) => p, - None => return false, - }; - + let doc_data = raw_style_set.borrow(); let name = Atom::from(name.as_str_unchecked()); - let computed_value = match inherited.get(&name) { - Some(v) => v, - None => return false, + let stylist = &doc_data.stylist; + let custom_registration = stylist.get_custom_property_registration(&name); + let computed_value = if custom_registration.map_or(true, |r| r.inherits) { + computed_values.custom_properties.inherited.as_ref().and_then(|m| m.get(&name)) + } else { + computed_values.custom_properties.non_inherited.as_ref().and_then(|m| m.get(&name)) + .or_else(|| custom_registration.and_then(|m| m.initial_value.as_ref())) }; - computed_value.to_css(&mut CssWriter::new(value)).unwrap(); - true + if let Some(v) = computed_value { + v.to_css(&mut CssWriter::new(value)).unwrap(); + true + } else { + false + } } #[no_mangle] pub extern "C" fn Servo_GetCustomPropertiesCount(computed_values: &ComputedValues) -> u32 { - // TODO(bug 1840478): Handle non-inherited properties. - match &computed_values.custom_properties().inherited { - Some(m) => m.len() as u32, - None => 0, - } + // Just expose the custom property items from custom_properties.inherited, + // and custom_properties.non_inherited. + // TODO(bug 1855629): We should probably expose all properties that don't + // have the guaranteed-invalid-value (including non-inherited properties + // with an initial value), not just the ones in the maps. + let properties = computed_values.custom_properties(); + (properties.inherited.as_ref().map_or(0, |m| m.len()) + + properties.non_inherited.as_ref().map_or(0, |m| m.len())) as u32 } #[no_mangle] @@ -7453,18 +7460,10 @@ pub extern "C" fn Servo_GetCustomPropertyNameAt( computed_values: &ComputedValues, index: u32, ) -> *mut nsAtom { - // TODO(bug 1840478): Handle non-inherited properties. - let inherited = match &computed_values.custom_properties.inherited { - Some(p) => p, - None => return ptr::null_mut(), - }; - - let property_name = match inherited.get_index(index as usize) { - Some((key, _value)) => key, - None => return ptr::null_mut(), - }; - - property_name.as_ptr() + match &computed_values.custom_properties.property_at(index as usize) { + Some((name, _value)) => name.as_ptr(), + None => ptr::null_mut(), + } } #[no_mangle] diff --git a/testing/web-platform/meta/css/css-cascade/layer-cssom-order-reverse-at-property.html.ini b/testing/web-platform/meta/css/css-cascade/layer-cssom-order-reverse-at-property.html.ini index 23a75258266d..d77ad9a4a5a1 100644 --- a/testing/web-platform/meta/css/css-cascade/layer-cssom-order-reverse-at-property.html.ini +++ b/testing/web-platform/meta/css/css-cascade/layer-cssom-order-reverse-at-property.html.ini @@ -1,8 +1,3 @@ [layer-cssom-order-reverse-at-property.html] expected: if (os == "android") and fission: [OK, TIMEOUT] - [Insert layer invalidates @property] - expected: FAIL - - [Delete layer invalidates @property] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-cascade/layer-property-override.html.ini b/testing/web-platform/meta/css/css-cascade/layer-property-override.html.ini index 75603e2b4a3e..6cf2d19fb9a5 100644 --- a/testing/web-platform/meta/css/css-cascade/layer-property-override.html.ini +++ b/testing/web-platform/meta/css/css-cascade/layer-property-override.html.ini @@ -1,14 +1,3 @@ [layer-property-override.html] expected: if (os == "android") and fission: [OK, TIMEOUT] - [@property override between layers] - expected: FAIL - - [@property override update with appended sheet 1] - expected: FAIL - - [@property override update with appended sheet 2] - expected: FAIL - - [@property unlayered overrides layered] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animate-invalid.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animate-invalid.html.ini deleted file mode 100644 index 8cd785265512..000000000000 --- a/testing/web-platform/meta/css/css-properties-values-api/animate-invalid.html.ini +++ /dev/null @@ -1,4 +0,0 @@ -[animate-invalid.html] - [Do not crash when animating to unresolved var()] - expected: FAIL - diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-angle-comma-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-angle-comma-list.html.ini index 77313bcfcb5d..439deb57cd2d 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-angle-comma-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-angle-comma-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type # with iterationComposite] expected: FAIL - - [Animating a custom property of type # with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-angle-space-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-angle-space-list.html.ini index 08e6e650b7a0..6659a70be4f0 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-angle-space-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-angle-space-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type + with iterationComposite] expected: FAIL - - [Animating a custom property of type + with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-color-comma-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-color-comma-list.html.ini index e5fd2d75744a..d820ec472367 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-color-comma-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-color-comma-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type # with iterationComposite] expected: FAIL - - [Animating a custom property of type # with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-color-space-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-color-space-list.html.ini index 66fd3c9a0fc2..5e5527e92b38 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-color-space-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-color-space-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type + with iterationComposite] expected: FAIL - - [Animating a custom property of type + with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-custom-ident.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-custom-ident.html.ini deleted file mode 100644 index bd548c452703..000000000000 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-custom-ident.html.ini +++ /dev/null @@ -1,9 +0,0 @@ -[custom-property-animation-custom-ident.html] - [Animating a custom property of type is discrete] - expected: FAIL - - [Animating a custom property of type + is discrete] - expected: FAIL - - [Animating a custom property of type # is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-image.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-image.html.ini deleted file mode 100644 index 1a77e948b114..000000000000 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-image.html.ini +++ /dev/null @@ -1,9 +0,0 @@ -[custom-property-animation-image.html] - [Animating a custom property of type is discrete] - expected: FAIL - - [Animating a custom property of type + is discrete] - expected: FAIL - - [Animating a custom property of type # is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-integer-comma-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-integer-comma-list.html.ini index bcf205f8cf9e..fc37a42166cc 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-integer-comma-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-integer-comma-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type # with iterationComposite] expected: FAIL - - [Animating a custom property of type # with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-integer-space-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-integer-space-list.html.ini index 46469bf7ec2b..7d7123b6734d 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-integer-space-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-integer-space-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type + with iterationComposite] expected: FAIL - - [Animating a custom property of type + with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-comma-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-comma-list.html.ini index b19aba5255e7..b023222f7c11 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-comma-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-comma-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type # with iterationComposite] expected: FAIL - - [Animating a custom property of type # with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-percentage-comma-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-percentage-comma-list.html.ini index ec057da2966d..f7cf9f586965 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-percentage-comma-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-percentage-comma-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type # with iterationComposite] expected: FAIL - - [Animating a custom property of type # with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-percentage-space-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-percentage-space-list.html.ini index 8762dc18dd2b..d950975c4b58 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-percentage-space-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-percentage-space-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type + with iterationComposite] expected: FAIL - - [Animating a custom property of type + with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-space-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-space-list.html.ini index 0d2118aff287..b32fe48826c9 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-space-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-length-space-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type + with iterationComposite] expected: FAIL - - [Animating a custom property of type + with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-number-comma-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-number-comma-list.html.ini index df4537f7a9af..13e6b587dde0 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-number-comma-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-number-comma-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type # with iterationComposite] expected: FAIL - - [Animating a custom property of type # with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-number-space-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-number-space-list.html.ini index 2d779955baa8..d21247a44479 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-number-space-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-number-space-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type + with iterationComposite] expected: FAIL - - [Animating a custom property of type + with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-percentage-comma-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-percentage-comma-list.html.ini index b56ff4418efa..4e4805c55480 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-percentage-comma-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-percentage-comma-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type # with iterationComposite] expected: FAIL - - [Animating a custom property of type # with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-percentage-space-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-percentage-space-list.html.ini index 9472b6dd7c8f..100facee73ca 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-percentage-space-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-percentage-space-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type + with iterationComposite] expected: FAIL - - [Animating a custom property of type + with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-resolution-comma-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-resolution-comma-list.html.ini index cfdea775146b..108978955086 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-resolution-comma-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-resolution-comma-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type # with iterationComposite] expected: FAIL - - [Animating a custom property of type # with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-resolution-space-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-resolution-space-list.html.ini index 10f4a613d0cf..92d63924932e 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-resolution-space-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-resolution-space-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type + with iterationComposite] expected: FAIL - - [Animating a custom property of type + with different lengths is discrete] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-time-comma-list.html.ini b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-time-comma-list.html.ini index 0ec423189e32..416d877c4d3c 100644 --- a/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-time-comma-list.html.ini +++ b/testing/web-platform/meta/css/css-properties-values-api/animation/custom-property-animation-time-comma-list.html.ini @@ -13,6 +13,3 @@ [Animating a custom property of type