style: Refactor vector types.

This fixes clamping of mask-size and moves it out of mako while at it.

Bug: 1462829
Reviewed-by: hiro,xidorn
MozReview-Commit-ID: 9hiTe63odna
This commit is contained in:
Emilio Cobos Álvarez 2018-05-18 22:06:25 +02:00
parent 3016a7f552
commit 32c6d5b7c6
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
18 changed files with 259 additions and 372 deletions

View file

@ -164,7 +164,7 @@ class Longhand(object):
allowed_in_keyframe_block=True, cast_type='u8', allowed_in_keyframe_block=True, cast_type='u8',
logical=False, alias=None, extra_prefixes=None, boxed=False, logical=False, alias=None, extra_prefixes=None, boxed=False,
flags=None, allowed_in_page_rule=False, allow_quirks=False, ignored_when_colors_disabled=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 self.name = name
if not spec: if not spec:
raise TypeError("Spec should be specified for %s" % name) raise TypeError("Spec should be specified for %s" % name)

View file

@ -3249,7 +3249,7 @@ fn static_assert() {
pub fn clone_scroll_snap_coordinate(&self) -> longhands::scroll_snap_coordinate::computed_value::T { 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(); 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')} ${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) %> <% copy_simple_image_array_property(name, shorthand, layer_field_name, field_name) %>
pub fn set_${ident}<I>(&mut self, v: I) pub fn set_${ident}<I>(&mut self, v: I)
where I: IntoIterator<Item=longhands::${ident}::computed_value::single_value::T>, where
I::IntoIter: ExactSizeIterator I: IntoIterator<Item=longhands::${ident}::computed_value::single_value::T>,
I::IntoIter: ExactSizeIterator,
{ {
use properties::longhands::${ident}::single_value::computed_value::T as Keyword; use properties::longhands::${ident}::single_value::computed_value::T as Keyword;
use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
@ -3791,7 +3792,7 @@ fn static_assert() {
% endfor % endfor
% endif % endif
longhands::${ident}::computed_value::T ( longhands::${ident}::computed_value::List(
self.gecko.${layer_field_name}.mLayers.iter() self.gecko.${layer_field_name}.mLayers.iter()
.take(self.gecko.${layer_field_name}.${field_name}Count as usize) .take(self.gecko.${layer_field_name}.${field_name}Count as usize)
.map(|ref layer| { .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() self.gecko.${image_layers_field}.mLayers.iter()
.take(self.gecko.${image_layers_field}.mRepeatCount as usize) .take(self.gecko.${image_layers_field}.mRepeatCount as usize)
.map(|ref layer| { .map(|ref layer| {
@ -3897,7 +3898,7 @@ fn static_assert() {
pub fn clone_${shorthand}_position_${orientation}(&self) 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::T( longhands::${shorthand}_position_${orientation}::computed_value::List(
self.gecko.${image_layers_field}.mLayers.iter() self.gecko.${image_layers_field}.mLayers.iter()
.take(self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count as usize) .take(self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count as usize)
.map(|position| position.mPosition.m${orientation.upper()}Position.into()) .map(|position| position.mPosition.m${orientation.upper()}Position.into())
@ -3941,11 +3942,11 @@ fn static_assert() {
BackgroundSize::Explicit { width: explicit_width, height: explicit_height } => { BackgroundSize::Explicit { width: explicit_width, height: explicit_height } => {
let mut w_type = nsStyleImageLayers_Size_DimensionType::eAuto; let mut w_type = nsStyleImageLayers_Size_DimensionType::eAuto;
let mut h_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; width = w;
w_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage; 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; height = h;
h_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage; h_type = nsStyleImageLayers_Size_DimensionType::eLengthPercentage;
} }
@ -3973,22 +3974,23 @@ fn static_assert() {
} }
</%self:simple_image_array_property> </%self:simple_image_array_property>
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::nsStyleCoord_CalcValue as CalcValue;
use gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType as DimensionType; 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; 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 { if ty == DimensionType::eAuto as u8 {
LengthOrPercentageOrAuto::Auto NonNegativeLengthOrPercentageOrAuto::auto()
} else { } else {
debug_assert_eq!(ty, DimensionType::eLengthPercentage as u8); 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| { self.gecko.${image_layers_field}.mLayers.iter().map(|ref layer| {
if DimensionType::eCover as u8 == layer.mSize.mWidthType { if DimensionType::eCover as u8 == layer.mSize.mWidthType {
debug_assert_eq!(layer.mSize.mHeightType, DimensionType::eCover as u8); 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 { pub fn clone_${shorthand}_image(&self) -> longhands::${shorthand}_image::computed_value::T {
use values::None_; use values::None_;
longhands::${shorthand}_image::computed_value::T( longhands::${shorthand}_image::computed_value::List(
self.gecko.${image_layers_field}.mLayers.iter() self.gecko.${image_layers_field}.mLayers.iter()
.take(self.gecko.${image_layers_field}.mImageCount as usize) .take(self.gecko.${image_layers_field}.mImageCount as usize)
.map(|ref layer| { .map(|ref layer| {
@ -4315,7 +4317,7 @@ fn static_assert() {
pub fn clone_box_shadow(&self) -> longhands::box_shadow::computed_value::T { 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(); 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) { 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)
} }
</%self:impl_trait> </%self:impl_trait>
@ -4681,7 +4683,7 @@ fn static_assert() {
pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T { 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(); 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) { pub fn set_line_height(&mut self, v: longhands::line_height::computed_value::T) {

View file

@ -8,7 +8,8 @@
%> %>
<%def name="predefined_type(name, type, initial_value, parse_method='parse', <%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)"> allow_quirks=False, allow_empty=False, **kwargs)">
<%def name="predefined_type_inner(name, type, initial_value, parse_method)"> <%def name="predefined_type_inner(name, type, initial_value, parse_method)">
#[allow(unused_imports)] #[allow(unused_imports)]
@ -77,10 +78,12 @@
We assume that the default/initial value is an empty vector for these. We assume that the default/initial value is an empty vector for these.
`initial_value` need not be defined for these. `initial_value` need not be defined for these.
</%doc> </%doc>
<%def name="vector_longhand(name, animation_value_type=None, allow_empty=False, separator='Comma', <%def name="vector_longhand(name, animation_value_type=None,
need_animatable=False, **kwargs)"> vector_animation_type=None, allow_empty=False,
separator='Comma',
**kwargs)">
<%call expr="longhand(name, animation_value_type=animation_value_type, vector=True, <%call expr="longhand(name, animation_value_type=animation_value_type, vector=True,
need_animatable=need_animatable, **kwargs)"> **kwargs)">
#[allow(unused_imports)] #[allow(unused_imports)]
use smallvec::SmallVec; use smallvec::SmallVec;
@ -115,36 +118,68 @@
% endif % endif
use values::computed::ComputedVecIter; 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": % if separator == "Comma":
#[css(comma)] #[css(comma)]
% endif % endif
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToAnimatedValue,
% if need_animatable or animation_value_type == "ComputedValue": ToCss)]
#[derive(Animate, ComputeSquaredDistance)] pub struct List<T>(
% endif
pub struct T(
% if not allow_empty: % if not allow_empty:
#[css(iterable)] #[css(iterable)]
% else: % else:
#[css(if_empty = "none", iterable)] #[css(if_empty = "none", iterable)]
% endif % endif
% if allow_empty and allow_empty != "NotInitial": % if allow_empty and allow_empty != "NotInitial":
pub Vec<single_value::T>, pub Vec<T>,
% else: % else:
pub SmallVec<[single_value::T; 1]>, pub SmallVec<[T; 1]>,
% endif % endif
); );
% if need_animatable or animation_value_type == "ComputedValue":
use values::animated::{ToAnimatedZero};
impl ToAnimatedZero for T { /// The computed value, effectively a list of single values.
#[inline] % if vector_animation_type:
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } % if not animation_value_type:
} Sorry, this is stupid but needed for now.
% endif % 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 = <List<single_value::T> as ToAnimatedValue>::AnimatedValue;
impl ToAnimatedZero for AnimatedList {
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
}
impl Animate for AnimatedList {
fn animate(
&self,
other: &Self,
procedure: Procedure,
) -> Result<Self, ()> {
Ok(List(
self.0.animate_${vector_animation_type}(&other.0, procedure)?
))
}
}
impl ComputeSquaredDistance for AnimatedList {
fn compute_squared_distance(
&self,
other: &Self,
) -> Result<SquaredDistance, ()> {
self.0.squared_distance_${vector_animation_type}(&other.0)
}
}
% endif
pub type T = List<single_value::T>;
pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>; pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>;
impl IntoIterator for T { impl IntoIterator for T {
@ -176,16 +211,18 @@
pub fn get_initial_value() -> computed_value::T { pub fn get_initial_value() -> computed_value::T {
% if allow_empty and allow_empty != "NotInitial": % if allow_empty and allow_empty != "NotInitial":
computed_value::T(vec![]) computed_value::List(vec![])
% else: % else:
let mut v = SmallVec::new(); let mut v = SmallVec::new();
v.push(single_value::get_initial_value()); v.push(single_value::get_initial_value());
computed_value::T(v) computed_value::List(v)
% endif % endif
} }
pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) pub fn parse<'i, 't>(
-> Result<SpecifiedValue, ParseError<'i>> { context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<SpecifiedValue, ParseError<'i>> {
use style_traits::Separator; use style_traits::Separator;
% if allow_empty: % if allow_empty:
@ -202,8 +239,10 @@
pub use self::single_value::SpecifiedValue as SingleSpecifiedValue; pub use self::single_value::SpecifiedValue as SingleSpecifiedValue;
impl SpecifiedValue { impl SpecifiedValue {
pub fn compute_iter<'a, 'cx, 'cx_a>(&'a self, context: &'cx Context<'cx_a>) pub fn compute_iter<'a, 'cx, 'cx_a>(
-> computed_value::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) computed_value::Iter::new(context, &self.0)
} }
} }
@ -213,7 +252,7 @@
#[inline] #[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T { 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] #[inline]

View file

@ -29,11 +29,10 @@ use std::mem::{self, ManuallyDrop};
#[cfg(feature = "gecko")] use hash::FnvHashMap; #[cfg(feature = "gecko")] use hash::FnvHashMap;
use style_traits::{KeywordsCollectFn, ParseError, SpecifiedValueInfo}; use style_traits::{KeywordsCollectFn, ParseError, SpecifiedValueInfo};
use super::ComputedValues; use super::ComputedValues;
use values::{CSSFloat, CustomIdent, Either}; use values::{CSSFloat, CustomIdent};
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
use values::animated::color::RGBA as AnimatedRGBA; use values::animated::color::RGBA as AnimatedRGBA;
use values::animated::effects::Filter as AnimatedFilter; use values::animated::effects::Filter as AnimatedFilter;
use values::animated::effects::FilterList as AnimatedFilterList;
use values::computed::{Angle, CalcLengthOrPercentage}; use values::computed::{Angle, CalcLengthOrPercentage};
use values::computed::{ClipRect, Context}; use values::computed::{ClipRect, Context};
use values::computed::{Length, LengthOrPercentage, LengthOrPercentageOrAuto}; 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::generics::font::{FontSettings as GenericFontSettings, FontTag, VariationValue};
use values::computed::font::FontVariationSettings; use values::computed::font::FontVariationSettings;
use values::generics::effects::Filter; use values::generics::effects::Filter;
use values::generics::position as generic_position;
use values::generics::svg::{SVGLength, SvgLengthOrPercentageOrNumber, SVGPaint}; use values::generics::svg::{SVGLength, SvgLengthOrPercentageOrNumber, SVGPaint};
use values::generics::svg::{SVGPaintKind, SVGStrokeDashArray, SVGOpacity}; use values::generics::svg::{SVGPaintKind, SVGStrokeDashArray, SVGOpacity};
use void::{self, Void}; use void::{self, Void};
/// <https://drafts.csswg.org/css-transitions/#animtype-repeatable-list>
pub trait RepeatableListAnimatable: Animate {}
/// Returns true if this nsCSSPropertyID is one of the animatable properties. /// Returns true if this nsCSSPropertyID is one of the animatable properties.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
@ -755,18 +751,45 @@ impl ToAnimatedZero for AnimationValue {
} }
} }
impl RepeatableListAnimatable for LengthOrPercentage {} /// A trait to abstract away the different kind of animations over a list that
impl RepeatableListAnimatable for Either<f32, LengthOrPercentage> {} /// there may be.
impl RepeatableListAnimatable for Either<NonNegativeNumber, NonNegativeLengthOrPercentage> {} pub trait ListAnimation<T> : Sized {
impl RepeatableListAnimatable for SvgLengthOrPercentageOrNumber<LengthOrPercentage, Number> {} /// <https://drafts.csswg.org/css-transitions/#animtype-repeatable-list>
fn animate_repeatable_list(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>
where
T: Animate;
macro_rules! repeated_vec_impl { /// <https://drafts.csswg.org/css-transitions/#animtype-repeatable-list>
($($ty:ty),*) => { fn squared_distance_repeatable_list(&self, other: &Self) -> Result<SquaredDistance, ()>
$(impl<T> Animate for $ty where
where T: ComputeSquaredDistance;
T: RepeatableListAnimatable,
{ /// This is the animation used for some of the types like shadows and
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> { /// 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<Self, ()>
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<SquaredDistance, ()>
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<Self, ()>
where
T: Animate,
{
// If the length of either list is zero, the least common multiple is undefined. // If the length of either list is zero, the least common multiple is undefined.
if self.is_empty() || other.is_empty() { if self.is_empty() || other.is_empty() {
return Err(()); return Err(());
@ -777,14 +800,14 @@ macro_rules! repeated_vec_impl {
this.animate(other, procedure) this.animate(other, procedure)
}).collect() }).collect()
} }
}
impl<T> ComputeSquaredDistance for $ty fn squared_distance_repeatable_list(
where &self,
T: ComputeSquaredDistance + RepeatableListAnimatable, other: &Self,
{ ) -> Result<SquaredDistance, ()>
#[inline] where
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { T: ComputeSquaredDistance,
{
if self.is_empty() || other.is_empty() { if self.is_empty() || other.is_empty() {
return Err(()); return Err(());
} }
@ -794,11 +817,59 @@ macro_rules! repeated_vec_impl {
this.compute_squared_distance(other) this.compute_squared_distance(other)
}).sum() }).sum()
} }
})*
}; fn animate_with_zero(
&self,
other: &Self,
procedure: Procedure,
) -> Result<Self, ()>
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<SquaredDistance, ()>
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<T>); animated_list_impl!(<T> for SmallVec<[T; 1]>);
animated_list_impl!(<T> for Vec<T>);
/// <https://drafts.csswg.org/css-transitions/#animtype-visibility> /// <https://drafts.csswg.org/css-transitions/#animtype-visibility>
impl Animate for Visibility { impl Animate for Visibility {
@ -1027,9 +1098,6 @@ impl<'a> Iterator for FontSettingTagIter<'a> {
} }
} }
impl<H, V> RepeatableListAnimatable for generic_position::Position<H, V>
where H: RepeatableListAnimatable, V: RepeatableListAnimatable {}
/// <https://drafts.csswg.org/css-transitions/#animtype-rect> /// <https://drafts.csswg.org/css-transitions/#animtype-rect>
impl Animate for ClipRect { impl Animate for ClipRect {
#[inline] #[inline]
@ -2668,27 +2736,16 @@ impl ComputeSquaredDistance for ComputedTransformOperation {
impl ComputeSquaredDistance for ComputedTransform { impl ComputeSquaredDistance for ComputedTransform {
#[inline] #[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
let list1 = &self.0; let squared_dist = self.0.squared_distance_with_zero(&other.0);
let list2 = &other.0;
let squared_dist: Result<SquaredDistance, _> = list1.iter().zip_longest(list2).map(|it| { // Roll back to matrix interpolation if there is any Err(()) in the
match it { // transform lists, such as mismatched transform functions.
EitherOrBoth::Both(this, other) => { if squared_dist.is_err() {
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 {
let matrix1: Matrix3D = self.to_transform_3d_matrix(None)?.0.into(); let matrix1: Matrix3D = self.to_transform_3d_matrix(None)?.0.into();
let matrix2: Matrix3D = other.to_transform_3d_matrix(None)?.0.into(); let matrix2: Matrix3D = other.to_transform_3d_matrix(None)?.0.into();
return matrix1.compute_squared_distance(&matrix2); return matrix1.compute_squared_distance(&matrix2);
} }
squared_dist squared_dist
} }
} }
@ -2828,7 +2885,7 @@ where
/// <https://www.w3.org/TR/SVG11/painting.html#StrokeDasharrayProperty> /// <https://www.w3.org/TR/SVG11/painting.html#StrokeDasharrayProperty>
impl<L> Animate for SVGStrokeDashArray<L> impl<L> Animate for SVGStrokeDashArray<L>
where where
L: Clone + RepeatableListAnimatable, L: Clone + Animate,
{ {
#[inline] #[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> { fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
@ -2838,7 +2895,22 @@ where
} }
match (self, other) { match (self, other) {
(&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref 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<L> ComputeSquaredDistance for SVGStrokeDashArray<L>
where
L: ComputeSquaredDistance,
{
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
match (self, other) {
(&SVGStrokeDashArray::Values(ref this), &SVGStrokeDashArray::Values(ref other)) => {
this.squared_distance_repeatable_list(other)
}, },
_ => Err(()), _ => Err(()),
} }
@ -2929,50 +3001,6 @@ impl ToAnimatedZero for AnimatedFilter {
} }
} }
impl Animate for AnimatedFilterList {
#[inline]
fn animate(
&self,
other: &Self,
procedure: Procedure,
) -> Result<Self, ()> {
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::<Result<Vec<_>, _>>()?))
}
}
impl ComputeSquaredDistance for AnimatedFilterList {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
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, /// A comparator to sort PropertyIds such that longhands are sorted before shorthands,
/// shorthands with fewer components are sorted before shorthands with more components, /// 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]. /// and otherwise shorthands are sorted by IDL name as defined by [Web Animations][property-order].

View file

@ -36,6 +36,7 @@ ${helpers.predefined_type("background-image", "ImageLayer",
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-" + axis, spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-" + axis,
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
vector=True, vector=True,
vector_animation_type="repeatable_list",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
)} )}
% endfor % endfor
@ -76,13 +77,15 @@ ${helpers.single_keyword("background-origin",
animation_value_type="discrete", animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER")} 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_value="computed::BackgroundSize::auto()",
initial_specified_value="specified::BackgroundSize::auto()", initial_specified_value="specified::BackgroundSize::auto()",
spec="https://drafts.csswg.org/css-backgrounds/#the-background-size", spec="https://drafts.csswg.org/css-backgrounds/#the-background-size",
vector=True, vector=True,
vector_animation_type="repeatable_list",
animation_value_type="BackgroundSizeList", animation_value_type="BackgroundSizeList",
need_animatable=True,
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
extra_prefixes="webkit")} extra_prefixes="webkit")}

View file

@ -24,6 +24,7 @@ ${helpers.predefined_type(
None, None,
vector=True, vector=True,
animation_value_type="AnimatedBoxShadowList", animation_value_type="AnimatedBoxShadowList",
vector_animation_type="with_zero",
extra_prefixes="webkit", extra_prefixes="webkit",
ignored_when_colors_disabled=True, ignored_when_colors_disabled=True,
flags="APPLIES_TO_FIRST_LETTER", flags="APPLIES_TO_FIRST_LETTER",
@ -45,6 +46,7 @@ ${helpers.predefined_type(
vector=True, vector=True,
separator="Space", separator="Space",
animation_value_type="AnimatedFilterList", animation_value_type="AnimatedFilterList",
vector_animation_type="with_zero",
extra_prefixes="webkit", extra_prefixes="webkit",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB", flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
spec="https://drafts.fxtf.org/filters/#propdef-filter", spec="https://drafts.fxtf.org/filters/#propdef-filter",

View file

@ -192,6 +192,7 @@ ${helpers.predefined_type(
"SimpleShadow", "SimpleShadow",
None, None,
vector=True, vector=True,
vector_animation_type="with_zero",
animation_value_type="AnimatedTextShadowList", animation_value_type="AnimatedTextShadowList",
ignored_when_colors_disabled=True, ignored_when_colors_disabled=True,
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",

View file

@ -103,6 +103,7 @@ ${helpers.predefined_type(
initial_specified_value="specified::PositionComponent::Center", initial_specified_value="specified::PositionComponent::Center",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position", spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position",
animation_value_type="ComputedValue", animation_value_type="ComputedValue",
vector_animation_type="repeatable_list",
vector=True, vector=True,
)} )}
% endfor % endfor
@ -126,26 +127,18 @@ ${helpers.single_keyword("mask-origin",
gecko_enum_prefix="StyleGeometryBox", gecko_enum_prefix="StyleGeometryBox",
animation_value_type="discrete", animation_value_type="discrete",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-origin")} spec="https://drafts.fxtf.org/css-masking/#propdef-mask-origin")}
${helpers.predefined_type(
<%helpers:longhand name="mask-size" products="gecko" animation_value_type="ComputedValue" extra_prefixes="webkit" "mask-size",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-size"> "background::BackgroundSize",
use properties::longhands::background_size; "computed::BackgroundSize::auto()",
pub use ::properties::longhands::background_size::SpecifiedValue; initial_specified_value="specified::BackgroundSize::auto()",
pub use ::properties::longhands::background_size::single_value as single_value; products="gecko",
pub use ::properties::longhands::background_size::computed_value as computed_value; extra_prefixes="webkit",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-size",
#[inline] animation_value_type="MaskSizeList",
pub fn get_initial_value() -> computed_value::T { vector=True,
background_size::get_initial_value() vector_animation_type="repeatable_list",
} )}
pub fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<SpecifiedValue, ParseError<'i>> {
background_size::parse(context, input)
}
</%helpers:longhand>
${helpers.single_keyword("mask-composite", ${helpers.single_keyword("mask-composite",
"add subtract intersect exclude", "add subtract intersect exclude",

View file

@ -2216,12 +2216,13 @@ pub mod style_structs {
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[inline] #[inline]
pub fn set_${longhand.ident}<I>(&mut self, v: I) pub fn set_${longhand.ident}<I>(&mut self, v: I)
where I: IntoIterator<Item = longhands::${longhand.ident} where
::computed_value::single_value::T>, I: IntoIterator<Item = longhands::${longhand.ident}
I::IntoIter: ExactSizeIterator ::computed_value::single_value::T>,
I::IntoIter: ExactSizeIterator
{ {
self.${longhand.ident} = longhands::${longhand.ident}::computed_value self.${longhand.ident} = longhands::${longhand.ident}::computed_value
::T(v.into_iter().collect()); ::List(v.into_iter().collect());
} }
% elif longhand.ident == "display": % elif longhand.ident == "display":
/// Set `display`. /// Set `display`.
@ -2404,7 +2405,7 @@ pub mod style_structs {
pub fn clone_${longhand.ident}( pub fn clone_${longhand.ident}(
&self, &self,
) -> longhands::${longhand.ident}::computed_value::T { ) -> longhands::${longhand.ident}::computed_value::T {
longhands::${longhand.ident}::computed_value::T( longhands::${longhand.ident}::computed_value::List(
self.${longhand.ident}_iter().collect() self.${longhand.ident}_iter().collect()
) )
} }

View file

@ -188,8 +188,10 @@
use values::specified::position::Position; use values::specified::position::Position;
use parser::Parse; use parser::Parse;
pub fn parse_value<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) pub fn parse_value<'i, 't>(
-> Result<Longhands, ParseError<'i>> { context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Longhands, ParseError<'i>> {
// Vec grows from 0 to 4 by default on first push(). So allocate with // 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 // 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 // overallocate. Note that we always push at least one item if parsing
@ -205,7 +207,8 @@
any = true; any = true;
Ok(()) Ok(())
})?; })?;
if any == false {
if !any {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
} }

View file

@ -4,13 +4,8 @@
//! Animated types for CSS values related to effects. //! 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"))] #[cfg(not(feature = "gecko"))]
use values::Impossible; use values::Impossible;
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
use values::animated::color::RGBA; use values::animated::color::RGBA;
use values::computed::{Angle, Number}; use values::computed::{Angle, Number};
use values::computed::length::Length; 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::Filter as GenericFilter;
use values::generics::effects::SimpleShadow as GenericSimpleShadow; use values::generics::effects::SimpleShadow as GenericSimpleShadow;
/// An animated value for the `box-shadow` property.
pub type BoxShadowList = ShadowList<BoxShadow>;
/// An animated value for the `text-shadow` property.
pub type TextShadowList = ShadowList<SimpleShadow>;
/// An animated value for shadow lists.
///
/// <https://drafts.csswg.org/css-transitions/#animtype-shadow-list>
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
#[derive(Clone, Debug, PartialEq)]
pub struct ShadowList<Shadow>(Vec<Shadow>);
/// An animated value for a single `box-shadow`. /// An animated value for a single `box-shadow`.
pub type BoxShadow = GenericBoxShadow<Option<RGBA>, Length, Length, Length>; pub type BoxShadow = GenericBoxShadow<Option<RGBA>, 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<Filter>);
/// An animated value for a single `filter`. /// An animated value for a single `filter`.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow, ComputedUrl>; pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow, ComputedUrl>;
@ -53,86 +30,6 @@ pub type Filter = GenericFilter<Angle, Number, Length, Impossible, Impossible>;
/// An animated value for the `drop-shadow()` filter. /// An animated value for the `drop-shadow()` filter.
pub type SimpleShadow = GenericSimpleShadow<Option<RGBA>, Length, Length>; pub type SimpleShadow = GenericSimpleShadow<Option<RGBA>, 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<S> Animate for ShadowList<S>
where
S: Animate + Clone + ToAnimatedZero,
{
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
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<S> ComputeSquaredDistance for ShadowList<S>
where
S: ComputeSquaredDistance + ToAnimatedZero,
{
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
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<S> ToAnimatedZero for ShadowList<S> {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
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 { impl ComputeSquaredDistance for BoxShadow {
#[inline] #[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
@ -143,24 +40,3 @@ impl ComputeSquaredDistance for BoxShadow {
self.spread.compute_squared_distance(&other.spread)?) 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<Self, ()> {
Ok(FilterList(vec![]))
}
}

View file

@ -11,6 +11,7 @@
use app_units::Au; use app_units::Au;
use euclid::{Point2D, Size2D}; use euclid::{Point2D, Size2D};
use smallvec::SmallVec; use smallvec::SmallVec;
use values::computed::length::CalcLengthOrPercentage;
use values::computed::Angle as ComputedAngle; use values::computed::Angle as ComputedAngle;
use values::computed::BorderCornerRadius as ComputedBorderCornerRadius; use values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
use values::computed::MaxLength as ComputedMaxLength; 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!(Au);
trivial_to_animated_value!(CalcLengthOrPercentage);
trivial_to_animated_value!(ComputedAngle); trivial_to_animated_value!(ComputedAngle);
trivial_to_animated_value!(ComputedUrl); trivial_to_animated_value!(ComputedUrl);
trivial_to_animated_value!(bool); trivial_to_animated_value!(bool);

View file

@ -4,85 +4,27 @@
//! Computed types for CSS values related to backgrounds. //! 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 std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss}; use style_traits::{CssWriter, ToCss};
use values::animated::{ToAnimatedValue, ToAnimatedZero};
use values::computed::{Context, ToComputedValue}; use values::computed::{Context, ToComputedValue};
use values::computed::length::LengthOrPercentageOrAuto; use values::computed::length::NonNegativeLengthOrPercentageOrAuto;
use values::generics::background::BackgroundSize as GenericBackgroundSize; use values::generics::background::BackgroundSize as GenericBackgroundSize;
use values::specified::background::BackgroundRepeat as SpecifiedBackgroundRepeat; use values::specified::background::BackgroundRepeat as SpecifiedBackgroundRepeat;
use values::specified::background::BackgroundRepeatKeyword; use values::specified::background::BackgroundRepeatKeyword;
/// A computed value for the `background-size` property. /// A computed value for the `background-size` property.
pub type BackgroundSize = GenericBackgroundSize<LengthOrPercentageOrAuto>; pub type BackgroundSize = GenericBackgroundSize<NonNegativeLengthOrPercentageOrAuto>;
impl BackgroundSize { impl BackgroundSize {
/// Returns `auto auto`. /// Returns `auto auto`.
pub fn auto() -> Self { pub fn auto() -> Self {
GenericBackgroundSize::Explicit { GenericBackgroundSize::Explicit {
width: LengthOrPercentageOrAuto::Auto, width: NonNegativeLengthOrPercentageOrAuto::auto(),
height: LengthOrPercentageOrAuto::Auto, height: NonNegativeLengthOrPercentageOrAuto::auto(),
} }
} }
} }
impl RepeatableListAnimatable for BackgroundSize {}
impl ToAnimatedZero for BackgroundSize {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
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: /// The computed value of the `background-repeat` property:
/// ///
/// https://drafts.csswg.org/css-backgrounds/#the-background-repeat /// https://drafts.csswg.org/css-backgrounds/#the-background-repeat

View file

@ -324,8 +324,8 @@ impl ToComputedValue for specified::CalcLengthOrPercentage {
#[allow(missing_docs)] #[allow(missing_docs)]
#[animate(fallback = "Self::animate_fallback")] #[animate(fallback = "Self::animate_fallback")]
#[css(derive_debug)] #[css(derive_debug)]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq, ToAnimatedZero, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq,
ToCss)] ToAnimatedValue, ToAnimatedZero, ToCss)]
#[distance(fallback = "Self::compute_squared_distance_fallback")] #[distance(fallback = "Self::compute_squared_distance_fallback")]
pub enum LengthOrPercentage { pub enum LengthOrPercentage {
Length(Length), Length(Length),

View file

@ -14,7 +14,7 @@ use values::generics::NonNegative;
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Default, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Default,
MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo, MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo,
ToAnimatedZero, ToComputedValue)] ToAnimatedValue, ToAnimatedZero, ToComputedValue)]
pub struct Percentage(pub CSSFloat); pub struct Percentage(pub CSSFloat);
impl Percentage { impl Percentage {

View file

@ -6,7 +6,8 @@
/// A generic value for the `background-size` property. /// A generic value for the `background-size` property.
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf,
PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero,
ToComputedValue, ToCss)]
pub enum BackgroundSize<LengthOrPercentageOrAuto> { pub enum BackgroundSize<LengthOrPercentageOrAuto> {
/// `<width> <height>` /// `<width> <height>`
Explicit { Explicit {

View file

@ -202,14 +202,13 @@ pub enum SVGLength<LengthType> {
} }
/// Generic value for stroke-dasharray. /// Generic value for stroke-dasharray.
#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, #[derive(Clone, Debug, MallocSizeOf, PartialEq,
SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)] SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)]
pub enum SVGStrokeDashArray<LengthType> { pub enum SVGStrokeDashArray<LengthType> {
/// `[ <length> | <percentage> | <number> ]#` /// `[ <length> | <percentage> | <number> ]#`
#[css(comma)] #[css(comma)]
Values( Values(
#[css(if_empty = "none", iterable)] #[css(if_empty = "none", iterable)]
#[distance(field_bound)]
Vec<LengthType>, Vec<LengthType>,
), ),
/// `context-value` /// `context-value`

View file

@ -9,30 +9,25 @@ use parser::{Parse, ParserContext};
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
use style_traits::ParseError; use style_traits::ParseError;
use values::generics::background::BackgroundSize as GenericBackgroundSize; 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. /// A specified value for the `background-size` property.
pub type BackgroundSize = GenericBackgroundSize<LengthOrPercentageOrAuto>; pub type BackgroundSize = GenericBackgroundSize<NonNegativeLengthOrPercentageOrAuto>;
impl Parse for BackgroundSize { impl Parse for BackgroundSize {
fn parse<'i, 't>( fn parse<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
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 let height = input
.try(|i| LengthOrPercentageOrAuto::parse_non_negative(context, i)) .try(|i| NonNegativeLengthOrPercentageOrAuto::parse(context, i))
.unwrap_or(LengthOrPercentageOrAuto::Auto); .unwrap_or(NonNegativeLengthOrPercentageOrAuto::auto());
return Ok(GenericBackgroundSize::Explicit { width, height }); return Ok(GenericBackgroundSize::Explicit { width, height });
} }
let location = input.current_source_location(); Ok(try_match_ident_ignore_ascii_case! { input,
let ident = input.expect_ident()?; "cover" => GenericBackgroundSize::Cover,
(match_ignore_ascii_case! { &ident, "contain" => GenericBackgroundSize::Contain,
"cover" => Ok(GenericBackgroundSize::Cover),
"contain" => Ok(GenericBackgroundSize::Contain),
_ => Err(()),
}).map_err(|()| {
location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
}) })
} }
} }
@ -41,8 +36,8 @@ impl BackgroundSize {
/// Returns `auto auto`. /// Returns `auto auto`.
pub fn auto() -> Self { pub fn auto() -> Self {
GenericBackgroundSize::Explicit { GenericBackgroundSize::Explicit {
width: LengthOrPercentageOrAuto::Auto, width: NonNegativeLengthOrPercentageOrAuto::auto(),
height: LengthOrPercentageOrAuto::Auto, height: NonNegativeLengthOrPercentageOrAuto::auto(),
} }
} }
} }