diff --git a/components/style/properties/data.py b/components/style/properties/data.py index df1c8d2890a..0ac42b365ee 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -164,7 +164,7 @@ class Longhand(object): allowed_in_keyframe_block=True, cast_type='u8', logical=False, alias=None, extra_prefixes=None, boxed=False, flags=None, allowed_in_page_rule=False, allow_quirks=False, ignored_when_colors_disabled=False, - vector=False, need_animatable=False, servo_restyle_damage="repaint"): + vector=False, servo_restyle_damage="repaint"): self.name = name if not spec: raise TypeError("Spec should be specified for %s" % name) diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 9d00239f86b..1fc486975fd 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -3249,7 +3249,7 @@ fn static_assert() { pub fn clone_scroll_snap_coordinate(&self) -> longhands::scroll_snap_coordinate::computed_value::T { let vec = self.gecko.mScrollSnapCoordinate.iter().map(|f| f.into()).collect(); - longhands::scroll_snap_coordinate::computed_value::T(vec) + longhands::scroll_snap_coordinate::computed_value::List(vec) } ${impl_css_url('_moz_binding', 'mBinding')} @@ -3755,8 +3755,9 @@ fn static_assert() { <% copy_simple_image_array_property(name, shorthand, layer_field_name, field_name) %> pub fn set_${ident}(&mut self, v: I) - where I: IntoIterator, - I::IntoIter: ExactSizeIterator + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, { use properties::longhands::${ident}::single_value::computed_value::T as Keyword; use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; @@ -3791,7 +3792,7 @@ fn static_assert() { % endfor % endif - longhands::${ident}::computed_value::T ( + longhands::${ident}::computed_value::List( self.gecko.${layer_field_name}.mLayers.iter() .take(self.gecko.${layer_field_name}.${field_name}Count as usize) .map(|ref layer| { @@ -3858,7 +3859,7 @@ fn static_assert() { } } - longhands::${shorthand}_repeat::computed_value::T ( + longhands::${shorthand}_repeat::computed_value::List( self.gecko.${image_layers_field}.mLayers.iter() .take(self.gecko.${image_layers_field}.mRepeatCount as usize) .map(|ref layer| { @@ -3897,7 +3898,7 @@ fn static_assert() { pub fn clone_${shorthand}_position_${orientation}(&self) -> longhands::${shorthand}_position_${orientation}::computed_value::T { - longhands::${shorthand}_position_${orientation}::computed_value::T( + longhands::${shorthand}_position_${orientation}::computed_value::List( self.gecko.${image_layers_field}.mLayers.iter() .take(self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count as usize) .map(|position| position.mPosition.m${orientation.upper()}Position.into()) @@ -3941,11 +3942,11 @@ fn static_assert() { BackgroundSize::Explicit { width: explicit_width, height: explicit_height } => { let mut w_type = nsStyleImageLayers_Size_DimensionType::eAuto; let mut h_type = nsStyleImageLayers_Size_DimensionType::eAuto; - if let Some(w) = explicit_width.to_calc_value() { + if let Some(w) = explicit_width.0.to_calc_value() { width = w; w_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage; } - if let Some(h) = explicit_height.to_calc_value() { + if let Some(h) = explicit_height.0.to_calc_value() { height = h; h_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage; } @@ -3973,22 +3974,23 @@ fn static_assert() { } - pub fn clone_${shorthand}_size(&self) -> longhands::background_size::computed_value::T { + pub fn clone_${shorthand}_size(&self) -> longhands::${shorthand}_size::computed_value::T { use gecko_bindings::structs::nsStyleCoord_CalcValue as CalcValue; use gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType as DimensionType; - use values::computed::LengthOrPercentageOrAuto; + use values::generics::NonNegative; + use values::computed::NonNegativeLengthOrPercentageOrAuto; use values::generics::background::BackgroundSize; - fn to_servo(value: CalcValue, ty: u8) -> LengthOrPercentageOrAuto { + fn to_servo(value: CalcValue, ty: u8) -> NonNegativeLengthOrPercentageOrAuto { if ty == DimensionType::eAuto as u8 { - LengthOrPercentageOrAuto::Auto + NonNegativeLengthOrPercentageOrAuto::auto() } else { debug_assert_eq!(ty, DimensionType::eLengthPercentage as u8); - value.into() + NonNegative(value.into()) } } - longhands::background_size::computed_value::T( + longhands::${shorthand}_size::computed_value::List( self.gecko.${image_layers_field}.mLayers.iter().map(|ref layer| { if DimensionType::eCover as u8 == layer.mSize.mWidthType { debug_assert_eq!(layer.mSize.mHeightType, DimensionType::eCover as u8); @@ -4059,7 +4061,7 @@ fn static_assert() { pub fn clone_${shorthand}_image(&self) -> longhands::${shorthand}_image::computed_value::T { use values::None_; - longhands::${shorthand}_image::computed_value::T( + longhands::${shorthand}_image::computed_value::List( self.gecko.${image_layers_field}.mLayers.iter() .take(self.gecko.${image_layers_field}.mImageCount as usize) .map(|ref layer| { @@ -4315,7 +4317,7 @@ fn static_assert() { pub fn clone_box_shadow(&self) -> longhands::box_shadow::computed_value::T { let buf = self.gecko.mBoxShadow.iter().map(|v| v.to_box_shadow()).collect(); - longhands::box_shadow::computed_value::T(buf) + longhands::box_shadow::computed_value::List(buf) } pub fn set_clip(&mut self, v: longhands::clip::computed_value::T) { @@ -4560,7 +4562,7 @@ fn static_assert() { _ => {}, } } - longhands::filter::computed_value::T(filters) + longhands::filter::computed_value::List(filters) } @@ -4681,7 +4683,7 @@ fn static_assert() { pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T { let buf = self.gecko.mTextShadow.iter().map(|v| v.to_simple_shadow()).collect(); - longhands::text_shadow::computed_value::T(buf) + longhands::text_shadow::computed_value::List(buf) } pub fn set_line_height(&mut self, v: longhands::line_height::computed_value::T) { diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index ff6670c3274..03b588ad654 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -8,7 +8,8 @@ %> <%def name="predefined_type(name, type, initial_value, parse_method='parse', - needs_context=True, vector=False, computed_type=None, initial_specified_value=None, + needs_context=True, vector=False, + computed_type=None, initial_specified_value=None, allow_quirks=False, allow_empty=False, **kwargs)"> <%def name="predefined_type_inner(name, type, initial_value, parse_method)"> #[allow(unused_imports)] @@ -77,10 +78,12 @@ We assume that the default/initial value is an empty vector for these. `initial_value` need not be defined for these. -<%def name="vector_longhand(name, animation_value_type=None, allow_empty=False, separator='Comma', - need_animatable=False, **kwargs)"> +<%def name="vector_longhand(name, animation_value_type=None, + vector_animation_type=None, allow_empty=False, + separator='Comma', + **kwargs)"> <%call expr="longhand(name, animation_value_type=animation_value_type, vector=True, - need_animatable=need_animatable, **kwargs)"> + **kwargs)"> #[allow(unused_imports)] use smallvec::SmallVec; @@ -115,36 +118,68 @@ % endif use values::computed::ComputedVecIter; - /// The computed value, effectively a list of single values. + /// The generic type defining the value for this property. % if separator == "Comma": #[css(comma)] % endif - #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] - % if need_animatable or animation_value_type == "ComputedValue": - #[derive(Animate, ComputeSquaredDistance)] - % endif - pub struct T( + #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, + ToCss)] + pub struct List( % if not allow_empty: #[css(iterable)] % else: #[css(if_empty = "none", iterable)] % endif % if allow_empty and allow_empty != "NotInitial": - pub Vec, + pub Vec, % else: - pub SmallVec<[single_value::T; 1]>, + pub SmallVec<[T; 1]>, % endif ); - % if need_animatable or animation_value_type == "ComputedValue": - use values::animated::{ToAnimatedZero}; - impl ToAnimatedZero for T { - #[inline] - fn to_animated_zero(&self) -> Result { Err(()) } - } + /// The computed value, effectively a list of single values. + % if vector_animation_type: + % if not animation_value_type: + Sorry, this is stupid but needed for now. % endif + use properties::animated_properties::ListAnimation; + use values::animated::{Animate, ToAnimatedValue, ToAnimatedZero, Procedure}; + use values::distance::{SquaredDistance, ComputeSquaredDistance}; + + // FIXME(emilio): For some reason rust thinks that this alias is + // unused, even though it's clearly used below? + #[allow(unused)] + type AnimatedList = as ToAnimatedValue>::AnimatedValue; + + impl ToAnimatedZero for AnimatedList { + fn to_animated_zero(&self) -> Result { Err(()) } + } + + impl Animate for AnimatedList { + fn animate( + &self, + other: &Self, + procedure: Procedure, + ) -> Result { + Ok(List( + self.0.animate_${vector_animation_type}(&other.0, procedure)? + )) + } + } + impl ComputeSquaredDistance for AnimatedList { + fn compute_squared_distance( + &self, + other: &Self, + ) -> Result { + self.0.squared_distance_${vector_animation_type}(&other.0) + } + } + % endif + + pub type T = List; + pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>; impl IntoIterator for T { @@ -176,16 +211,18 @@ pub fn get_initial_value() -> computed_value::T { % if allow_empty and allow_empty != "NotInitial": - computed_value::T(vec![]) + computed_value::List(vec![]) % else: let mut v = SmallVec::new(); v.push(single_value::get_initial_value()); - computed_value::T(v) + computed_value::List(v) % endif } - pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) - -> Result> { + pub fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { use style_traits::Separator; % if allow_empty: @@ -202,8 +239,10 @@ pub use self::single_value::SpecifiedValue as SingleSpecifiedValue; impl SpecifiedValue { - pub fn compute_iter<'a, 'cx, 'cx_a>(&'a self, context: &'cx Context<'cx_a>) - -> computed_value::Iter<'a, 'cx, 'cx_a> { + pub fn compute_iter<'a, 'cx, 'cx_a>( + &'a self, + context: &'cx Context<'cx_a>, + ) -> computed_value::Iter<'a, 'cx, 'cx_a> { computed_value::Iter::new(context, &self.0) } } @@ -213,7 +252,7 @@ #[inline] fn to_computed_value(&self, context: &Context) -> computed_value::T { - computed_value::T(self.compute_iter(context).collect()) + computed_value::List(self.compute_iter(context).collect()) } #[inline] diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index fa6166e17ae..057360c9499 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -29,11 +29,10 @@ use std::mem::{self, ManuallyDrop}; #[cfg(feature = "gecko")] use hash::FnvHashMap; use style_traits::{KeywordsCollectFn, ParseError, SpecifiedValueInfo}; use super::ComputedValues; -use values::{CSSFloat, CustomIdent, Either}; +use values::{CSSFloat, CustomIdent}; use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; use values::animated::color::RGBA as AnimatedRGBA; use values::animated::effects::Filter as AnimatedFilter; -use values::animated::effects::FilterList as AnimatedFilterList; use values::computed::{Angle, CalcLengthOrPercentage}; use values::computed::{ClipRect, Context}; use values::computed::{Length, LengthOrPercentage, LengthOrPercentageOrAuto}; @@ -53,13 +52,10 @@ use values::distance::{ComputeSquaredDistance, SquaredDistance}; use values::generics::font::{FontSettings as GenericFontSettings, FontTag, VariationValue}; use values::computed::font::FontVariationSettings; use values::generics::effects::Filter; -use values::generics::position as generic_position; use values::generics::svg::{SVGLength, SvgLengthOrPercentageOrNumber, SVGPaint}; use values::generics::svg::{SVGPaintKind, SVGStrokeDashArray, SVGOpacity}; use void::{self, Void}; -/// -pub trait RepeatableListAnimatable: Animate {} /// Returns true if this nsCSSPropertyID is one of the animatable properties. #[cfg(feature = "gecko")] @@ -755,18 +751,45 @@ impl ToAnimatedZero for AnimationValue { } } -impl RepeatableListAnimatable for LengthOrPercentage {} -impl RepeatableListAnimatable for Either {} -impl RepeatableListAnimatable for Either {} -impl RepeatableListAnimatable for SvgLengthOrPercentageOrNumber {} +/// A trait to abstract away the different kind of animations over a list that +/// there may be. +pub trait ListAnimation : Sized { + /// + fn animate_repeatable_list(&self, other: &Self, procedure: Procedure) -> Result + where + T: Animate; -macro_rules! repeated_vec_impl { - ($($ty:ty),*) => { - $(impl Animate for $ty - where - T: RepeatableListAnimatable, - { - fn animate(&self, other: &Self, procedure: Procedure) -> Result { + /// + fn squared_distance_repeatable_list(&self, other: &Self) -> Result + where + T: ComputeSquaredDistance; + + /// This is the animation used for some of the types like shadows and + /// filters, where the interpolation happens with the zero value if one of + /// the sides is not present. + fn animate_with_zero(&self, other: &Self, procedure: Procedure) -> Result + where + T: Animate + Clone + ToAnimatedZero; + + /// This is the animation used for some of the types like shadows and + /// filters, where the interpolation happens with the zero value if one of + /// the sides is not present. + fn squared_distance_with_zero(&self, other: &Self) -> Result + where + T: ToAnimatedZero + ComputeSquaredDistance; +} + +macro_rules! animated_list_impl { + (<$t:ident> for $ty:ty) => { + impl<$t> ListAnimation<$t> for $ty { + fn animate_repeatable_list( + &self, + other: &Self, + procedure: Procedure, + ) -> Result + where + T: Animate, + { // If the length of either list is zero, the least common multiple is undefined. if self.is_empty() || other.is_empty() { return Err(()); @@ -777,14 +800,14 @@ macro_rules! repeated_vec_impl { this.animate(other, procedure) }).collect() } - } - impl ComputeSquaredDistance for $ty - where - T: ComputeSquaredDistance + RepeatableListAnimatable, - { - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { + fn squared_distance_repeatable_list( + &self, + other: &Self, + ) -> Result + where + T: ComputeSquaredDistance, + { if self.is_empty() || other.is_empty() { return Err(()); } @@ -794,11 +817,59 @@ macro_rules! repeated_vec_impl { this.compute_squared_distance(other) }).sum() } - })* - }; + + fn animate_with_zero( + &self, + other: &Self, + procedure: Procedure, + ) -> Result + where + T: Animate + Clone + ToAnimatedZero + { + if procedure == Procedure::Add { + return Ok( + self.iter().chain(other.iter()).cloned().collect() + ); + } + self.iter().zip_longest(other.iter()).map(|it| { + match it { + EitherOrBoth::Both(this, other) => { + this.animate(other, procedure) + }, + EitherOrBoth::Left(this) => { + this.animate(&this.to_animated_zero()?, procedure) + }, + EitherOrBoth::Right(other) => { + other.to_animated_zero()?.animate(other, procedure) + } + } + }).collect() + } + + fn squared_distance_with_zero( + &self, + other: &Self, + ) -> Result + where + T: ToAnimatedZero + ComputeSquaredDistance + { + self.iter().zip_longest(other.iter()).map(|it| { + match it { + EitherOrBoth::Both(this, other) => { + this.compute_squared_distance(other) + }, + EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => { + list.to_animated_zero()?.compute_squared_distance(list) + }, + } + }).sum() + } + } + } } -repeated_vec_impl!(SmallVec<[T; 1]>, Vec); +animated_list_impl!( for SmallVec<[T; 1]>); +animated_list_impl!( for Vec); /// impl Animate for Visibility { @@ -1027,9 +1098,6 @@ impl<'a> Iterator for FontSettingTagIter<'a> { } } -impl RepeatableListAnimatable for generic_position::Position - where H: RepeatableListAnimatable, V: RepeatableListAnimatable {} - /// impl Animate for ClipRect { #[inline] @@ -2668,27 +2736,16 @@ impl ComputeSquaredDistance for ComputedTransformOperation { impl ComputeSquaredDistance for ComputedTransform { #[inline] fn compute_squared_distance(&self, other: &Self) -> Result { - let list1 = &self.0; - let list2 = &other.0; + let squared_dist = self.0.squared_distance_with_zero(&other.0); - let squared_dist: Result = list1.iter().zip_longest(list2).map(|it| { - match it { - EitherOrBoth::Both(this, other) => { - this.compute_squared_distance(other) - }, - EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => { - list.to_animated_zero()?.compute_squared_distance(list) - }, - } - }).sum(); - - // Roll back to matrix interpolation if there is any Err(()) in the transform lists, such - // as mismatched transform functions. - if let Err(_) = squared_dist { + // Roll back to matrix interpolation if there is any Err(()) in the + // transform lists, such as mismatched transform functions. + if squared_dist.is_err() { let matrix1: Matrix3D = self.to_transform_3d_matrix(None)?.0.into(); let matrix2: Matrix3D = other.to_transform_3d_matrix(None)?.0.into(); return matrix1.compute_squared_distance(&matrix2); } + squared_dist } } @@ -2828,7 +2885,7 @@ where /// impl Animate for SVGStrokeDashArray where - L: Clone + RepeatableListAnimatable, + L: Clone + Animate, { #[inline] fn animate(&self, other: &Self, procedure: Procedure) -> Result { @@ -2838,7 +2895,22 @@ where } match (self, other) { (&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref other)) => { - Ok(SVGStrokeDashArray::Values(this.animate(other, procedure)?)) + Ok(SVGStrokeDashArray::Values(this.animate_repeatable_list(other, procedure)?)) + }, + _ => Err(()), + } + } +} + +impl ComputeSquaredDistance for SVGStrokeDashArray +where + L: ComputeSquaredDistance, +{ + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result { + match (self, other) { + (&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref other)) => { + this.squared_distance_repeatable_list(other) }, _ => Err(()), } @@ -2929,50 +3001,6 @@ impl ToAnimatedZero for AnimatedFilter { } } -impl Animate for AnimatedFilterList { - #[inline] - fn animate( - &self, - other: &Self, - procedure: Procedure, - ) -> Result { - if procedure == Procedure::Add { - return Ok(AnimatedFilterList( - self.0.iter().chain(other.0.iter()).cloned().collect(), - )); - } - Ok(AnimatedFilterList(self.0.iter().zip_longest(other.0.iter()).map(|it| { - match it { - EitherOrBoth::Both(this, other) => { - this.animate(other, procedure) - }, - EitherOrBoth::Left(this) => { - this.animate(&this.to_animated_zero()?, procedure) - }, - EitherOrBoth::Right(other) => { - other.to_animated_zero()?.animate(other, procedure) - }, - } - }).collect::, _>>()?)) - } -} - -impl ComputeSquaredDistance for AnimatedFilterList { - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - self.0.iter().zip_longest(other.0.iter()).map(|it| { - match it { - EitherOrBoth::Both(this, other) => { - this.compute_squared_distance(other) - }, - EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => { - list.to_animated_zero()?.compute_squared_distance(list) - }, - } - }).sum() - } -} - /// A comparator to sort PropertyIds such that longhands are sorted before shorthands, /// shorthands with fewer components are sorted before shorthands with more components, /// and otherwise shorthands are sorted by IDL name as defined by [Web Animations][property-order]. diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs index a1f1b039434..3366376466a 100644 --- a/components/style/properties/longhand/background.mako.rs +++ b/components/style/properties/longhand/background.mako.rs @@ -36,6 +36,7 @@ ${helpers.predefined_type("background-image", "ImageLayer", spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-" + axis, animation_value_type="ComputedValue", vector=True, + vector_animation_type="repeatable_list", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", )} % endfor @@ -76,13 +77,15 @@ ${helpers.single_keyword("background-origin", animation_value_type="discrete", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER")} -${helpers.predefined_type("background-size", "BackgroundSize", +${helpers.predefined_type( + "background-size", + "BackgroundSize", initial_value="computed::BackgroundSize::auto()", initial_specified_value="specified::BackgroundSize::auto()", spec="https://drafts.csswg.org/css-backgrounds/#the-background-size", vector=True, + vector_animation_type="repeatable_list", animation_value_type="BackgroundSizeList", - need_animatable=True, flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", extra_prefixes="webkit")} diff --git a/components/style/properties/longhand/effects.mako.rs b/components/style/properties/longhand/effects.mako.rs index 30493bd270d..674340c391a 100644 --- a/components/style/properties/longhand/effects.mako.rs +++ b/components/style/properties/longhand/effects.mako.rs @@ -24,6 +24,7 @@ ${helpers.predefined_type( None, vector=True, animation_value_type="AnimatedBoxShadowList", + vector_animation_type="with_zero", extra_prefixes="webkit", ignored_when_colors_disabled=True, flags="APPLIES_TO_FIRST_LETTER", @@ -45,6 +46,7 @@ ${helpers.predefined_type( vector=True, separator="Space", animation_value_type="AnimatedFilterList", + vector_animation_type="with_zero", extra_prefixes="webkit", flags="CREATES_STACKING_CONTEXT FIXPOS_CB", spec="https://drafts.fxtf.org/filters/#propdef-filter", diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index 975d7eabe26..62819a78cbc 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -192,6 +192,7 @@ ${helpers.predefined_type( "SimpleShadow", None, vector=True, + vector_animation_type="with_zero", animation_value_type="AnimatedTextShadowList", ignored_when_colors_disabled=True, flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", diff --git a/components/style/properties/longhand/svg.mako.rs b/components/style/properties/longhand/svg.mako.rs index bea30301eb2..3236495fc26 100644 --- a/components/style/properties/longhand/svg.mako.rs +++ b/components/style/properties/longhand/svg.mako.rs @@ -103,6 +103,7 @@ ${helpers.predefined_type( initial_specified_value="specified::PositionComponent::Center", spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position", animation_value_type="ComputedValue", + vector_animation_type="repeatable_list", vector=True, )} % endfor @@ -126,26 +127,18 @@ ${helpers.single_keyword("mask-origin", gecko_enum_prefix="StyleGeometryBox", animation_value_type="discrete", spec="https://drafts.fxtf.org/css-masking/#propdef-mask-origin")} - -<%helpers:longhand name="mask-size" products="gecko" animation_value_type="ComputedValue" extra_prefixes="webkit" - spec="https://drafts.fxtf.org/css-masking/#propdef-mask-size"> - use properties::longhands::background_size; - pub use ::properties::longhands::background_size::SpecifiedValue; - pub use ::properties::longhands::background_size::single_value as single_value; - pub use ::properties::longhands::background_size::computed_value as computed_value; - - #[inline] - pub fn get_initial_value() -> computed_value::T { - background_size::get_initial_value() - } - - pub fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - background_size::parse(context, input) - } - +${helpers.predefined_type( + "mask-size", + "background::BackgroundSize", + "computed::BackgroundSize::auto()", + initial_specified_value="specified::BackgroundSize::auto()", + products="gecko", + extra_prefixes="webkit", + spec="https://drafts.fxtf.org/css-masking/#propdef-mask-size", + animation_value_type="MaskSizeList", + vector=True, + vector_animation_type="repeatable_list", +)} ${helpers.single_keyword("mask-composite", "add subtract intersect exclude", diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index b39d93aff01..f28c04e795b 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -2216,12 +2216,13 @@ pub mod style_structs { #[allow(non_snake_case)] #[inline] pub fn set_${longhand.ident}(&mut self, v: I) - where I: IntoIterator, - I::IntoIter: ExactSizeIterator + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator { self.${longhand.ident} = longhands::${longhand.ident}::computed_value - ::T(v.into_iter().collect()); + ::List(v.into_iter().collect()); } % elif longhand.ident == "display": /// Set `display`. @@ -2404,7 +2405,7 @@ pub mod style_structs { pub fn clone_${longhand.ident}( &self, ) -> longhands::${longhand.ident}::computed_value::T { - longhands::${longhand.ident}::computed_value::T( + longhands::${longhand.ident}::computed_value::List( self.${longhand.ident}_iter().collect() ) } diff --git a/components/style/properties/shorthand/mask.mako.rs b/components/style/properties/shorthand/mask.mako.rs index d38eedb5854..aa73c77e46b 100644 --- a/components/style/properties/shorthand/mask.mako.rs +++ b/components/style/properties/shorthand/mask.mako.rs @@ -188,8 +188,10 @@ use values::specified::position::Position; use parser::Parse; - pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) - -> Result> { + pub fn parse_value<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { // Vec grows from 0 to 4 by default on first push(). So allocate with // capacity 1, so in the common case of only one item we don't way // overallocate. Note that we always push at least one item if parsing @@ -205,7 +207,8 @@ any = true; Ok(()) })?; - if any == false { + + if !any { return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); } diff --git a/components/style/values/animated/effects.rs b/components/style/values/animated/effects.rs index e0f4cf7b7c0..d0463365fc2 100644 --- a/components/style/values/animated/effects.rs +++ b/components/style/values/animated/effects.rs @@ -4,13 +4,8 @@ //! Animated types for CSS values related to effects. -use properties::longhands::box_shadow::computed_value::T as ComputedBoxShadowList; -use properties::longhands::filter::computed_value::T as ComputedFilterList; -use properties::longhands::text_shadow::computed_value::T as ComputedTextShadowList; -use std::cmp; #[cfg(not(feature = "gecko"))] use values::Impossible; -use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; use values::animated::color::RGBA; use values::computed::{Angle, Number}; use values::computed::length::Length; @@ -21,27 +16,9 @@ use values::generics::effects::BoxShadow as GenericBoxShadow; use values::generics::effects::Filter as GenericFilter; use values::generics::effects::SimpleShadow as GenericSimpleShadow; -/// An animated value for the `box-shadow` property. -pub type BoxShadowList = ShadowList; - -/// An animated value for the `text-shadow` property. -pub type TextShadowList = ShadowList; - -/// An animated value for shadow lists. -/// -/// -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] -#[derive(Clone, Debug, PartialEq)] -pub struct ShadowList(Vec); - /// An animated value for a single `box-shadow`. pub type BoxShadow = GenericBoxShadow, Length, Length, Length>; -/// An animated value for the `filter` property. -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] -#[derive(Clone, Debug, PartialEq)] -pub struct FilterList(pub Vec); - /// An animated value for a single `filter`. #[cfg(feature = "gecko")] pub type Filter = GenericFilter; @@ -53,86 +30,6 @@ pub type Filter = GenericFilter; /// An animated value for the `drop-shadow()` filter. pub type SimpleShadow = GenericSimpleShadow, Length, Length>; -impl ToAnimatedValue for ComputedBoxShadowList { - type AnimatedValue = BoxShadowList; - - #[inline] - fn to_animated_value(self) -> Self::AnimatedValue { - ShadowList(self.0.to_animated_value()) - } - - #[inline] - fn from_animated_value(animated: Self::AnimatedValue) -> Self { - ComputedBoxShadowList(ToAnimatedValue::from_animated_value(animated.0)) - } -} - -impl Animate for ShadowList -where - S: Animate + Clone + ToAnimatedZero, -{ - #[inline] - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - if procedure == Procedure::Add { - return Ok(ShadowList(self.0.iter().chain(&other.0).cloned().collect())); - } - // FIXME(nox): Use itertools here, to avoid the need for `unreachable!`. - let max_len = cmp::max(self.0.len(), other.0.len()); - let mut shadows = Vec::with_capacity(max_len); - for i in 0..max_len { - shadows.push(match (self.0.get(i), other.0.get(i)) { - (Some(shadow), Some(other)) => shadow.animate(other, procedure)?, - (Some(shadow), None) => shadow.animate(&shadow.to_animated_zero()?, procedure)?, - (None, Some(shadow)) => shadow.to_animated_zero()?.animate(shadow, procedure)?, - (None, None) => unreachable!(), - }); - } - Ok(ShadowList(shadows)) - } -} - -impl ComputeSquaredDistance for ShadowList -where - S: ComputeSquaredDistance + ToAnimatedZero, -{ - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - use itertools::{EitherOrBoth, Itertools}; - - self.0 - .iter() - .zip_longest(other.0.iter()) - .map(|it| match it { - EitherOrBoth::Both(from, to) => from.compute_squared_distance(to), - EitherOrBoth::Left(list) | EitherOrBoth::Right(list) => { - list.compute_squared_distance(&list.to_animated_zero()?) - }, - }) - .sum() - } -} - -impl ToAnimatedZero for ShadowList { - #[inline] - fn to_animated_zero(&self) -> Result { - Ok(ShadowList(vec![])) - } -} - -impl ToAnimatedValue for ComputedTextShadowList { - type AnimatedValue = TextShadowList; - - #[inline] - fn to_animated_value(self) -> Self::AnimatedValue { - ShadowList(self.0.to_animated_value()) - } - - #[inline] - fn from_animated_value(animated: Self::AnimatedValue) -> Self { - ComputedTextShadowList(ToAnimatedValue::from_animated_value(animated.0)) - } -} - impl ComputeSquaredDistance for BoxShadow { #[inline] fn compute_squared_distance(&self, other: &Self) -> Result { @@ -143,24 +40,3 @@ impl ComputeSquaredDistance for BoxShadow { self.spread.compute_squared_distance(&other.spread)?) } } - -impl ToAnimatedValue for ComputedFilterList { - type AnimatedValue = FilterList; - - #[inline] - fn to_animated_value(self) -> Self::AnimatedValue { - FilterList(self.0.to_animated_value()) - } - - #[inline] - fn from_animated_value(animated: Self::AnimatedValue) -> Self { - ComputedFilterList(ToAnimatedValue::from_animated_value(animated.0)) - } -} - -impl ToAnimatedZero for FilterList { - #[inline] - fn to_animated_zero(&self) -> Result { - Ok(FilterList(vec![])) - } -} diff --git a/components/style/values/animated/mod.rs b/components/style/values/animated/mod.rs index 533d917be6f..2bb80df0ec7 100644 --- a/components/style/values/animated/mod.rs +++ b/components/style/values/animated/mod.rs @@ -11,6 +11,7 @@ use app_units::Au; use euclid::{Point2D, Size2D}; use smallvec::SmallVec; +use values::computed::length::CalcLengthOrPercentage; use values::computed::Angle as ComputedAngle; use values::computed::BorderCornerRadius as ComputedBorderCornerRadius; use values::computed::MaxLength as ComputedMaxLength; @@ -257,6 +258,7 @@ macro_rules! trivial_to_animated_value { } trivial_to_animated_value!(Au); +trivial_to_animated_value!(CalcLengthOrPercentage); trivial_to_animated_value!(ComputedAngle); trivial_to_animated_value!(ComputedUrl); trivial_to_animated_value!(bool); diff --git a/components/style/values/computed/background.rs b/components/style/values/computed/background.rs index beca0a7ca7e..e94bece983e 100644 --- a/components/style/values/computed/background.rs +++ b/components/style/values/computed/background.rs @@ -4,85 +4,27 @@ //! Computed types for CSS values related to backgrounds. -use properties::animated_properties::RepeatableListAnimatable; -use properties::longhands::background_size::computed_value::T as BackgroundSizeList; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; -use values::animated::{ToAnimatedValue, ToAnimatedZero}; use values::computed::{Context, ToComputedValue}; -use values::computed::length::LengthOrPercentageOrAuto; +use values::computed::length::NonNegativeLengthOrPercentageOrAuto; use values::generics::background::BackgroundSize as GenericBackgroundSize; use values::specified::background::BackgroundRepeat as SpecifiedBackgroundRepeat; use values::specified::background::BackgroundRepeatKeyword; /// A computed value for the `background-size` property. -pub type BackgroundSize = GenericBackgroundSize; +pub type BackgroundSize = GenericBackgroundSize; impl BackgroundSize { /// Returns `auto auto`. pub fn auto() -> Self { GenericBackgroundSize::Explicit { - width: LengthOrPercentageOrAuto::Auto, - height: LengthOrPercentageOrAuto::Auto, + width: NonNegativeLengthOrPercentageOrAuto::auto(), + height: NonNegativeLengthOrPercentageOrAuto::auto(), } } } -impl RepeatableListAnimatable for BackgroundSize {} - -impl ToAnimatedZero for BackgroundSize { - #[inline] - fn to_animated_zero(&self) -> Result { - Err(()) - } -} - -impl ToAnimatedValue for BackgroundSize { - type AnimatedValue = Self; - - #[inline] - fn to_animated_value(self) -> Self { - self - } - - #[inline] - fn from_animated_value(animated: Self::AnimatedValue) -> Self { - use values::computed::{Length, Percentage}; - let clamp_animated_value = |value: LengthOrPercentageOrAuto| -> LengthOrPercentageOrAuto { - match value { - LengthOrPercentageOrAuto::Length(len) => { - LengthOrPercentageOrAuto::Length(Length::new(len.px().max(0.))) - }, - LengthOrPercentageOrAuto::Percentage(percent) => { - LengthOrPercentageOrAuto::Percentage(Percentage(percent.0.max(0.))) - }, - _ => value, - } - }; - match animated { - GenericBackgroundSize::Explicit { width, height } => GenericBackgroundSize::Explicit { - width: clamp_animated_value(width), - height: clamp_animated_value(height), - }, - _ => animated, - } - } -} - -impl ToAnimatedValue for BackgroundSizeList { - type AnimatedValue = Self; - - #[inline] - fn to_animated_value(self) -> Self { - self - } - - #[inline] - fn from_animated_value(animated: Self::AnimatedValue) -> Self { - BackgroundSizeList(ToAnimatedValue::from_animated_value(animated.0)) - } -} - /// The computed value of the `background-repeat` property: /// /// https://drafts.csswg.org/css-backgrounds/#the-background-repeat diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index beb33553d7f..2518b8c0a3f 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -324,8 +324,8 @@ impl ToComputedValue for specified::CalcLengthOrPercentage { #[allow(missing_docs)] #[animate(fallback = "Self::animate_fallback")] #[css(derive_debug)] -#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq, ToAnimatedZero, - ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq, + ToAnimatedValue, ToAnimatedZero, ToCss)] #[distance(fallback = "Self::compute_squared_distance_fallback")] pub enum LengthOrPercentage { Length(Length), diff --git a/components/style/values/computed/percentage.rs b/components/style/values/computed/percentage.rs index 653532aea6c..718d74335b7 100644 --- a/components/style/values/computed/percentage.rs +++ b/components/style/values/computed/percentage.rs @@ -14,7 +14,7 @@ use values::generics::NonNegative; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Default, MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo, - ToAnimatedZero, ToComputedValue)] + ToAnimatedValue, ToAnimatedZero, ToComputedValue)] pub struct Percentage(pub CSSFloat); impl Percentage { diff --git a/components/style/values/generics/background.rs b/components/style/values/generics/background.rs index ad42fcfb555..b25b00514d0 100644 --- a/components/style/values/generics/background.rs +++ b/components/style/values/generics/background.rs @@ -6,7 +6,8 @@ /// A generic value for the `background-size` property. #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, - PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] + PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, + ToComputedValue, ToCss)] pub enum BackgroundSize { /// ` ` Explicit { diff --git a/components/style/values/generics/svg.rs b/components/style/values/generics/svg.rs index 9246175068c..0fbaacf2283 100644 --- a/components/style/values/generics/svg.rs +++ b/components/style/values/generics/svg.rs @@ -202,14 +202,13 @@ pub enum SVGLength { } /// Generic value for stroke-dasharray. -#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)] pub enum SVGStrokeDashArray { /// `[ | | ]#` #[css(comma)] Values( #[css(if_empty = "none", iterable)] - #[distance(field_bound)] Vec, ), /// `context-value` diff --git a/components/style/values/specified/background.rs b/components/style/values/specified/background.rs index b9feb8b8e27..d7c4ec629ca 100644 --- a/components/style/values/specified/background.rs +++ b/components/style/values/specified/background.rs @@ -9,30 +9,25 @@ use parser::{Parse, ParserContext}; use selectors::parser::SelectorParseErrorKind; use style_traits::ParseError; use values::generics::background::BackgroundSize as GenericBackgroundSize; -use values::specified::length::LengthOrPercentageOrAuto; +use values::specified::length::NonNegativeLengthOrPercentageOrAuto; /// A specified value for the `background-size` property. -pub type BackgroundSize = GenericBackgroundSize; +pub type BackgroundSize = GenericBackgroundSize; impl Parse for BackgroundSize { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { - if let Ok(width) = input.try(|i| LengthOrPercentageOrAuto::parse_non_negative(context, i)) { + if let Ok(width) = input.try(|i| NonNegativeLengthOrPercentageOrAuto::parse(context, i)) { let height = input - .try(|i| LengthOrPercentageOrAuto::parse_non_negative(context, i)) - .unwrap_or(LengthOrPercentageOrAuto::Auto); + .try(|i| NonNegativeLengthOrPercentageOrAuto::parse(context, i)) + .unwrap_or(NonNegativeLengthOrPercentageOrAuto::auto()); return Ok(GenericBackgroundSize::Explicit { width, height }); } - let location = input.current_source_location(); - let ident = input.expect_ident()?; - (match_ignore_ascii_case! { &ident, - "cover" => Ok(GenericBackgroundSize::Cover), - "contain" => Ok(GenericBackgroundSize::Contain), - _ => Err(()), - }).map_err(|()| { - location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())) + Ok(try_match_ident_ignore_ascii_case! { input, + "cover" => GenericBackgroundSize::Cover, + "contain" => GenericBackgroundSize::Contain, }) } } @@ -41,8 +36,8 @@ impl BackgroundSize { /// Returns `auto auto`. pub fn auto() -> Self { GenericBackgroundSize::Explicit { - width: LengthOrPercentageOrAuto::Auto, - height: LengthOrPercentageOrAuto::Auto, + width: NonNegativeLengthOrPercentageOrAuto::auto(), + height: NonNegativeLengthOrPercentageOrAuto::auto(), } } }