aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-08-28 10:13:13 -0500
committerGitHub <noreply@github.com>2017-08-28 10:13:13 -0500
commita266e96d28b7960b4fb0b236c3e8e93cf70f09b0 (patch)
tree139e748d7cb22f0796640677119ee0ca65e3d067
parent96b4e064a1f0b0fc1ee2811d0c1b528f85a718c6 (diff)
parentba4136b5a8da58a6130aa3fab0654764bcdda25f (diff)
downloadservo-a266e96d28b7960b4fb0b236c3e8e93cf70f09b0.tar.gz
servo-a266e96d28b7960b4fb0b236c3e8e93cf70f09b0.zip
Auto merge of #18239 - servo:derive-all-the-things, r=emilio
Refactor how we handle trait bounds in style_derive <!-- Reviewable:start --> This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18239) <!-- Reviewable:end -->
-rw-r--r--components/style/properties/helpers/animated_properties.mako.rs222
-rw-r--r--components/style/properties/longhand/font.mako.rs30
-rw-r--r--components/style/values/animated/effects.rs26
-rw-r--r--components/style/values/animated/mod.rs23
-rw-r--r--components/style/values/computed/angle.rs25
-rw-r--r--components/style/values/computed/background.rs19
-rw-r--r--components/style/values/computed/image.rs55
-rw-r--r--components/style/values/computed/length.rs219
-rw-r--r--components/style/values/computed/mod.rs6
-rw-r--r--components/style/values/distance.rs11
-rw-r--r--components/style/values/generics/background.rs5
-rw-r--r--components/style/values/generics/basic_shape.rs53
-rw-r--r--components/style/values/generics/effects.rs4
-rw-r--r--components/style/values/generics/grid.rs98
-rw-r--r--components/style/values/generics/image.rs6
-rw-r--r--components/style/values/generics/svg.rs7
-rw-r--r--components/style/values/specified/grid.rs61
-rw-r--r--components/style_derive/animate.rs66
-rw-r--r--components/style_derive/cg.rs344
-rw-r--r--components/style_derive/compute_squared_distance.rs29
-rw-r--r--components/style_derive/has_viewport_percentage.rs5
-rw-r--r--components/style_derive/lib.rs8
-rw-r--r--components/style_derive/to_animated_value.rs18
-rw-r--r--components/style_derive/to_animated_zero.rs49
-rw-r--r--components/style_derive/to_computed_value.rs51
-rw-r--r--components/style_derive/to_css.rs45
-rw-r--r--components/style_traits/values.rs8
27 files changed, 649 insertions, 844 deletions
diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs
index e3c831c8bc9..4c2057f61d9 100644
--- a/components/style/properties/helpers/animated_properties.mako.rs
+++ b/components/style/properties/helpers/animated_properties.mako.rs
@@ -48,9 +48,10 @@ use values::animated::effects::TextShadowList as AnimatedTextShadowList;
use values::computed::{Angle, BorderCornerRadius, CalcLengthOrPercentage};
use values::computed::{ClipRect, Context, ComputedUrl, ComputedValueAsSpecified};
use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
-use values::computed::{LengthOrPercentageOrNone, MaxLength, MozLength, NonNegativeAu};
+use values::computed::{LengthOrPercentageOrNone, MaxLength, NonNegativeAu};
use values::computed::{NonNegativeNumber, Number, NumberOrPercentage, Percentage};
use values::computed::{PositiveIntegerOrAuto, ToComputedValue};
+#[cfg(feature = "gecko")] use values::computed::MozLength;
use values::computed::length::{NonNegativeLengthOrAuto, NonNegativeLengthOrNormal};
use values::computed::length::NonNegativeLengthOrPercentage;
use values::distance::{ComputeSquaredDistance, SquaredDistance};
@@ -811,73 +812,6 @@ impl Animate for CalcLengthOrPercentage {
}
}
-/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
-impl Animate for LengthOrPercentage {
- #[inline]
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- match (self, other) {
- (
- &LengthOrPercentage::Length(ref this),
- &LengthOrPercentage::Length(ref other),
- ) => {
- Ok(LengthOrPercentage::Length(this.animate(other, procedure)?))
- },
- (
- &LengthOrPercentage::Percentage(ref this),
- &LengthOrPercentage::Percentage(ref other),
- ) => {
- Ok(LengthOrPercentage::Percentage(this.animate(other, procedure)?))
- },
- (this, other) => {
- // Special handling for zero values since these should not require calc().
- if this.is_definitely_zero() {
- return other.to_animated_zero()?.animate(other, procedure);
- }
- if other.is_definitely_zero() {
- return this.animate(&this.to_animated_zero()?, procedure);
- }
-
- let this = CalcLengthOrPercentage::from(*this);
- let other = CalcLengthOrPercentage::from(*other);
- Ok(LengthOrPercentage::Calc(this.animate(&other, procedure)?))
- }
- }
- }
-}
-
-/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
-impl Animate for LengthOrPercentageOrAuto {
- #[inline]
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- match (self, other) {
- (
- &LengthOrPercentageOrAuto::Length(ref this),
- &LengthOrPercentageOrAuto::Length(ref other),
- ) => {
- Ok(LengthOrPercentageOrAuto::Length(this.animate(other, procedure)?))
- },
- (
- &LengthOrPercentageOrAuto::Percentage(ref this),
- &LengthOrPercentageOrAuto::Percentage(ref other),
- ) => {
- Ok(LengthOrPercentageOrAuto::Percentage(
- this.animate(other, procedure)?,
- ))
- },
- (&LengthOrPercentageOrAuto::Auto, &LengthOrPercentageOrAuto::Auto) => {
- Ok(LengthOrPercentageOrAuto::Auto)
- },
- (this, other) => {
- let this: Option<CalcLengthOrPercentage> = From::from(*this);
- let other: Option<CalcLengthOrPercentage> = From::from(*other);
- Ok(LengthOrPercentageOrAuto::Calc(
- this.animate(&other, procedure)?.ok_or(())?,
- ))
- },
- }
- }
-}
-
impl ToAnimatedZero for LengthOrPercentageOrAuto {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
@@ -892,39 +826,6 @@ impl ToAnimatedZero for LengthOrPercentageOrAuto {
}
}
-/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
-impl Animate for LengthOrPercentageOrNone {
- #[inline]
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- match (self, other) {
- (
- &LengthOrPercentageOrNone::Length(ref this),
- &LengthOrPercentageOrNone::Length(ref other),
- ) => {
- Ok(LengthOrPercentageOrNone::Length(this.animate(other, procedure)?))
- },
- (
- &LengthOrPercentageOrNone::Percentage(ref this),
- &LengthOrPercentageOrNone::Percentage(ref other),
- ) => {
- Ok(LengthOrPercentageOrNone::Percentage(
- this.animate(other, procedure)?,
- ))
- }
- (&LengthOrPercentageOrNone::None, &LengthOrPercentageOrNone::None) => {
- Ok(LengthOrPercentageOrNone::None)
- },
- (this, other) => {
- let this = <Option<CalcLengthOrPercentage>>::from(*this);
- let other = <Option<CalcLengthOrPercentage>>::from(*other);
- Ok(LengthOrPercentageOrNone::Calc(
- this.animate(&other, procedure)?.ok_or(())?,
- ))
- },
- }
- }
-}
-
impl ToAnimatedZero for LengthOrPercentageOrNone {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
@@ -939,54 +840,6 @@ impl ToAnimatedZero for LengthOrPercentageOrNone {
}
}
-/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
-impl Animate for MozLength {
- #[inline]
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- match (self, other) {
- (
- &MozLength::LengthOrPercentageOrAuto(ref this),
- &MozLength::LengthOrPercentageOrAuto(ref other),
- ) => {
- Ok(MozLength::LengthOrPercentageOrAuto(
- this.animate(other, procedure)?,
- ))
- }
- _ => Err(()),
- }
- }
-}
-
-impl ToAnimatedZero for MozLength {
- #[inline]
- fn to_animated_zero(&self) -> Result<Self, ()> {
- match *self {
- MozLength::LengthOrPercentageOrAuto(ref length) => {
- Ok(MozLength::LengthOrPercentageOrAuto(length.to_animated_zero()?))
- },
- _ => Err(())
- }
- }
-}
-
-/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
-impl Animate for MaxLength {
- #[inline]
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- match (self, other) {
- (
- &MaxLength::LengthOrPercentageOrNone(ref this),
- &MaxLength::LengthOrPercentageOrNone(ref other),
- ) => {
- Ok(MaxLength::LengthOrPercentageOrNone(
- this.animate(other, procedure)?,
- ))
- },
- _ => Err(()),
- }
- }
-}
-
impl ToAnimatedZero for MaxLength {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
@@ -2431,27 +2284,6 @@ pub type IntermediateSVGPaint = SVGPaint<AnimatedRGBA, ComputedUrl>;
/// Animated SVGPaintKind
pub type IntermediateSVGPaintKind = SVGPaintKind<AnimatedRGBA, ComputedUrl>;
-impl Animate for IntermediateSVGPaint {
- #[inline]
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- Ok(IntermediateSVGPaint {
- kind: self.kind.animate(&other.kind, procedure)?,
- fallback: self.fallback.animate(&other.fallback, procedure)?,
- })
- }
-}
-
-impl ComputeSquaredDistance for IntermediateSVGPaint {
- #[inline]
- fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
- // FIXME(nox): This should be derived.
- Ok(
- self.kind.compute_squared_distance(&other.kind)? +
- self.fallback.compute_squared_distance(&other.fallback)?,
- )
- }
-}
-
impl ToAnimatedZero for IntermediateSVGPaint {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
@@ -2462,56 +2294,6 @@ impl ToAnimatedZero for IntermediateSVGPaint {
}
}
-impl Animate for IntermediateSVGPaintKind {
- #[inline]
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- match (self, other) {
- (&SVGPaintKind::Color(ref this), &SVGPaintKind::Color(ref other)) => {
- Ok(SVGPaintKind::Color(this.animate(other, procedure)?))
- },
- (&SVGPaintKind::ContextFill, &SVGPaintKind::ContextFill) => Ok(SVGPaintKind::ContextFill),
- (&SVGPaintKind::ContextStroke, &SVGPaintKind::ContextStroke) => Ok(SVGPaintKind::ContextStroke),
- _ => {
- // FIXME: Context values should be interpolable with colors,
- // Gecko doesn't implement this behavior either.
- Err(())
- }
- }
- }
-}
-
-impl ComputeSquaredDistance for IntermediateSVGPaintKind {
- #[inline]
- fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
- match (self, other) {
- (&SVGPaintKind::Color(ref this), &SVGPaintKind::Color(ref other)) => {
- this.compute_squared_distance(other)
- }
- (&SVGPaintKind::None, &SVGPaintKind::None) |
- (&SVGPaintKind::ContextFill, &SVGPaintKind::ContextFill) |
- (&SVGPaintKind::ContextStroke, &SVGPaintKind::ContextStroke) => {
- Ok(SquaredDistance::Value(0.))
- },
- _ => Err(())
- }
- }
-}
-
-impl ToAnimatedZero for IntermediateSVGPaintKind {
- #[inline]
- fn to_animated_zero(&self) -> Result<Self, ()> {
- match *self {
- SVGPaintKind::Color(ref color) => {
- Ok(SVGPaintKind::Color(color.to_animated_zero()?))
- },
- SVGPaintKind::None |
- SVGPaintKind::ContextFill |
- SVGPaintKind::ContextStroke => Ok(self.clone()),
- _ => Err(()),
- }
- }
-}
-
impl From<NonNegativeLengthOrPercentage> for NumberOrPercentage {
fn from(lop: NonNegativeLengthOrPercentage) -> NumberOrPercentage {
lop.0.into()
diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs
index e4d257d02a6..7dc51dca3d4 100644
--- a/components/style/properties/longhand/font.mako.rs
+++ b/components/style/properties/longhand/font.mako.rs
@@ -1116,12 +1116,12 @@ ${helpers.single_keyword_system("font-variant-caps",
pub mod computed_value {
use values::CSSFloat;
- use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
- use values::distance::{ComputeSquaredDistance, SquaredDistance};
+ use values::animated::{ToAnimatedValue, ToAnimatedZero};
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- #[derive(Clone, Copy, Debug, PartialEq, ToCss)]
+ #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToCss)]
pub enum T {
+ #[animation(error)]
None,
Number(CSSFloat),
}
@@ -1136,27 +1136,6 @@ ${helpers.single_keyword_system("font-variant-caps",
}
}
- impl Animate for T {
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- match (self, other) {
- (&T::Number(ref number), &T::Number(ref other)) => {
- Ok(T::Number(number.animate(other, procedure)?))
- },
- _ => Err(()),
- }
- }
- }
-
- impl ComputeSquaredDistance for T {
- #[inline]
- fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
- match (self, other) {
- (&T::Number(ref this), &T::Number(ref other)) => this.compute_squared_distance(other),
- _ => Err(()),
- }
- }
- }
-
impl ToAnimatedZero for T {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
@@ -2265,11 +2244,8 @@ https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control-
predefined_type="Number" gecko_ffi_name="mScriptSizeMultiplier"
spec="Internal (not web-exposed)"
internal="True">
- use values::computed::ComputedValueAsSpecified;
pub use self::computed_value::T as SpecifiedValue;
- impl ComputedValueAsSpecified for SpecifiedValue {}
-
pub mod computed_value {
pub type T = f32;
}
diff --git a/components/style/values/animated/effects.rs b/components/style/values/animated/effects.rs
index cdde2894549..eb03bd9565b 100644
--- a/components/style/values/animated/effects.rs
+++ b/components/style/values/animated/effects.rs
@@ -139,21 +139,6 @@ impl ToAnimatedValue for ComputedTextShadowList {
}
}
-// FIXME(nox): This could be derived if we implement Animate for bool.
-impl Animate for BoxShadow {
- #[inline]
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- if self.inset != other.inset {
- return Err(());
- }
- Ok(BoxShadow {
- base: self.base.animate(&other.base, procedure)?,
- spread: self.spread.animate(&other.spread, procedure)?,
- inset: self.inset,
- })
- }
-}
-
impl ComputeSquaredDistance for BoxShadow {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
@@ -167,17 +152,6 @@ impl ComputeSquaredDistance for BoxShadow {
}
}
-impl ToAnimatedZero for BoxShadow {
- #[inline]
- fn to_animated_zero(&self) -> Result<Self, ()> {
- Ok(BoxShadow {
- base: self.base.to_animated_zero()?,
- spread: self.spread.to_animated_zero()?,
- inset: self.inset,
- })
- }
-}
-
impl ToAnimatedValue for ComputedFilterList {
type AnimatedValue = FilterList;
diff --git a/components/style/values/animated/mod.rs b/components/style/values/animated/mod.rs
index 71f6e2bd4db..c2d42192fdd 100644
--- a/components/style/values/animated/mod.rs
+++ b/components/style/values/animated/mod.rs
@@ -28,7 +28,19 @@ use values::specified::url::SpecifiedUrl;
pub mod color;
pub mod effects;
-/// Animating from one value to another.
+/// Animate from one value to another.
+///
+/// This trait is derivable with `#[derive(Animate)]`. The derived
+/// implementation uses a `match` expression with identical patterns for both
+/// `self` and `other`, calling `Animate::animate` on each fields of the values.
+/// If a field is annotated with `#[animation(constant)]`, the two values should
+/// be equal or an error is returned.
+///
+/// If a variant is annotated with `#[animation(error)]`, the corresponding
+/// `match` arm is not generated.
+///
+/// If the two values are not similar, an error is returned unless a fallback
+/// function has been specified through `#[animate(fallback)]`.
pub trait Animate: Sized {
/// Animate a value towards another one, given an animation procedure.
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>;
@@ -51,6 +63,8 @@ pub enum Procedure {
/// Conversion between computed values and intermediate values for animations.
///
/// Notably, colors are represented as four floats during animations.
+///
+/// This trait is derivable with `#[derive(ToAnimatedValue)]`.
pub trait ToAnimatedValue {
/// The type of the animated value.
type AnimatedValue;
@@ -66,6 +80,13 @@ pub trait ToAnimatedValue {
pub trait AnimatedValueAsComputed {}
/// Returns a value similar to `self` that represents zero.
+///
+/// This trait is derivable with `#[derive(ToAnimatedValue)]`. If a field is
+/// annotated with `#[animation(constant)]`, a clone of its value will be used
+/// instead of calling `ToAnimatedZero::to_animated_zero` on it.
+///
+/// If a variant is annotated with `#[animation(error)]`, the corresponding
+/// `match` arm is not generated.
pub trait ToAnimatedZero: Sized {
/// Returns a value that, when added with an underlying value, will produce the underlying
/// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from
diff --git a/components/style/values/computed/angle.rs b/components/style/values/computed/angle.rs
index d5461d1cbf9..467a9501196 100644
--- a/components/style/values/computed/angle.rs
+++ b/components/style/values/computed/angle.rs
@@ -12,8 +12,10 @@ use values::animated::{Animate, Procedure};
use values::distance::{ComputeSquaredDistance, SquaredDistance};
/// A computed angle.
+#[animate(fallback = "Self::animate_fallback")]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
-#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, PartialOrd, ToAnimatedZero)]
+#[derive(Animate, Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
+#[derive(PartialOrd, ToAnimatedZero)]
pub enum Angle {
/// An angle with degree unit.
Degree(CSSFloat),
@@ -62,26 +64,11 @@ impl Angle {
pub fn zero() -> Self {
Angle::Radian(0.0)
}
-}
-/// https://drafts.csswg.org/css-transitions/#animtype-number
-impl Animate for Angle {
+ /// https://drafts.csswg.org/css-transitions/#animtype-number
#[inline]
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- match (self, other) {
- (&Angle::Degree(ref this), &Angle::Degree(ref other)) => {
- Ok(Angle::Degree(this.animate(other, procedure)?))
- },
- (&Angle::Gradian(ref this), &Angle::Gradian(ref other)) => {
- Ok(Angle::Gradian(this.animate(other, procedure)?))
- },
- (&Angle::Turn(ref this), &Angle::Turn(ref other)) => {
- Ok(Angle::Turn(this.animate(other, procedure)?))
- },
- _ => {
- Ok(Angle::from_radians(self.radians().animate(&other.radians(), procedure)?))
- },
- }
+ fn animate_fallback(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+ Ok(Angle::from_radians(self.radians().animate(&other.radians(), procedure)?))
}
}
diff --git a/components/style/values/computed/background.rs b/components/style/values/computed/background.rs
index 82b6ba74f28..f3180c54ebe 100644
--- a/components/style/values/computed/background.rs
+++ b/components/style/values/computed/background.rs
@@ -6,7 +6,7 @@
use properties::animated_properties::RepeatableListAnimatable;
use properties::longhands::background_size::computed_value::T as BackgroundSizeList;
-use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
+use values::animated::{ToAnimatedValue, ToAnimatedZero};
use values::computed::length::LengthOrPercentageOrAuto;
use values::generics::background::BackgroundSize as GenericBackgroundSize;
@@ -15,23 +15,6 @@ pub type BackgroundSize = GenericBackgroundSize<LengthOrPercentageOrAuto>;
impl RepeatableListAnimatable for BackgroundSize {}
-impl Animate for BackgroundSize {
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- match (self, other) {
- (
- &GenericBackgroundSize::Explicit { width: self_width, height: self_height },
- &GenericBackgroundSize::Explicit { width: other_width, height: other_height },
- ) => {
- Ok(GenericBackgroundSize::Explicit {
- width: self_width.animate(&other_width, procedure)?,
- height: self_height.animate(&other_height, procedure)?,
- })
- }
- _ => Err(()),
- }
- }
-}
-
impl ToAnimatedZero for BackgroundSize {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs
index a4a51b7bae6..952e213ccb9 100644
--- a/components/style/values/computed/image.rs
+++ b/components/style/values/computed/image.rs
@@ -18,8 +18,7 @@ use values::generics::image::{CompatMode, ColorStop as GenericColorStop, EndingS
use values::generics::image::{Gradient as GenericGradient, GradientItem as GenericGradientItem};
use values::generics::image::{Image as GenericImage, GradientKind as GenericGradientKind};
use values::generics::image::{LineDirection as GenericLineDirection, MozImageRect as GenericMozImageRect};
-use values::specified::image::{Gradient as SpecifiedGradient, LineDirection as SpecifiedLineDirection};
-use values::specified::image::{GradientKind as SpecifiedGradientKind};
+use values::specified::image::LineDirection as SpecifiedLineDirection;
use values::specified::position::{X, Y};
/// A computed image layer.
@@ -181,55 +180,3 @@ impl ToComputedValue for SpecifiedLineDirection {
}
}
}
-
-impl ToComputedValue for SpecifiedGradient {
- type ComputedValue = Gradient;
-
- fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
- Self::ComputedValue {
- kind: self.kind.to_computed_value(context),
- items: self.items.to_computed_value(context),
- repeating: self.repeating,
- compat_mode: self.compat_mode
- }
- }
-
- fn from_computed_value(computed: &Self::ComputedValue) -> Self {
- Self {
- kind: SpecifiedGradientKind::from_computed_value(&computed.kind),
- items: ToComputedValue::from_computed_value(&computed.items),
- repeating: computed.repeating,
- compat_mode: computed.compat_mode
- }
- }
-}
-
-impl ToComputedValue for SpecifiedGradientKind {
- type ComputedValue = GradientKind;
-
- fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
- match self {
- &GenericGradientKind::Linear(ref line_direction) => {
- GenericGradientKind::Linear(line_direction.to_computed_value(context))
- },
- &GenericGradientKind::Radial(ref ending_shape, ref position, ref angle) => {
- GenericGradientKind::Radial(ending_shape.to_computed_value(context),
- position.to_computed_value(context),
- angle.map(|angle| angle.to_computed_value(context)))
- }
- }
- }
-
- fn from_computed_value(computed: &Self::ComputedValue) -> Self {
- match *computed {
- GenericGradientKind::Linear(line_direction) => {
- GenericGradientKind::Linear(SpecifiedLineDirection::from_computed_value(&line_direction))
- },
- GenericGradientKind::Radial(ending_shape, position, angle) => {
- GenericGradientKind::Radial(ToComputedValue::from_computed_value(&ending_shape),
- ToComputedValue::from_computed_value(&position),
- angle.map(|angle| ToComputedValue::from_computed_value(&angle)))
- }
- }
- }
-}
diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs
index b4f4cfc5101..d29f5aa87fc 100644
--- a/components/style/values/computed/length.rs
+++ b/components/style/values/computed/length.rs
@@ -11,7 +11,7 @@ use style_traits::ToCss;
use style_traits::values::specified::AllowedLengthType;
use super::{Number, ToComputedValue, Context, Percentage};
use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
-use values::animated::ToAnimatedZero;
+use values::animated::{Animate, Procedure, ToAnimatedZero};
use values::computed::{NonNegativeAu, NonNegativeNumber};
use values::distance::{ComputeSquaredDistance, SquaredDistance};
use values::generics::NonNegative;
@@ -64,26 +64,16 @@ impl ToComputedValue for specified::Length {
}
}
-#[derive(Clone, Copy, Debug, PartialEq)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Clone, Copy, Debug, PartialEq, ToAnimatedZero)]
pub struct CalcLengthOrPercentage {
+ #[animation(constant)]
pub clamping_mode: AllowedLengthType,
length: Au,
pub percentage: Option<Percentage>,
}
-impl ToAnimatedZero for CalcLengthOrPercentage {
- #[inline]
- fn to_animated_zero(&self) -> Result<Self, ()> {
- Ok(CalcLengthOrPercentage {
- clamping_mode: self.clamping_mode,
- length: self.length.to_animated_zero()?,
- percentage: self.percentage.to_animated_zero()?,
- })
- }
-}
-
impl ComputeSquaredDistance for CalcLengthOrPercentage {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
@@ -285,28 +275,47 @@ impl ToComputedValue for specified::CalcLengthOrPercentage {
}
#[allow(missing_docs)]
+#[animate(fallback = "Self::animate_fallback")]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[derive(Clone, Copy, PartialEq, ToAnimatedZero, ToCss)]
+#[css(derive_debug)]
+#[derive(Animate, Clone, ComputeSquaredDistance, Copy, PartialEq)]
+#[derive(ToAnimatedZero, ToCss)]
+#[distance(fallback = "Self::compute_squared_distance_fallback")]
pub enum LengthOrPercentage {
Length(Au),
Percentage(Percentage),
Calc(CalcLengthOrPercentage),
}
-impl ComputeSquaredDistance for LengthOrPercentage {
- #[inline]
- fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
- match (self, other) {
- (&LengthOrPercentage::Length(ref this), &LengthOrPercentage::Length(ref other)) => {
- this.compute_squared_distance(other)
- },
- (&LengthOrPercentage::Percentage(ref this), &LengthOrPercentage::Percentage(ref other)) => {
- this.compute_squared_distance(other)
- },
- (this, other) => {
- CalcLengthOrPercentage::compute_squared_distance(&(*this).into(), &(*other).into())
- }
+impl LengthOrPercentage {
+ /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
+ fn animate_fallback(
+ &self,
+ other: &Self,
+ procedure: Procedure,
+ ) -> Result<Self, ()> {
+ // Special handling for zero values since these should not require calc().
+ if self.is_definitely_zero() {
+ return other.to_animated_zero()?.animate(other, procedure);
}
+ if other.is_definitely_zero() {
+ return self.animate(&self.to_animated_zero()?, procedure);
+ }
+
+ let this = CalcLengthOrPercentage::from(*self);
+ let other = CalcLengthOrPercentage::from(*other);
+ Ok(LengthOrPercentage::Calc(this.animate(&other, procedure)?))
+ }
+
+ #[inline]
+ fn compute_squared_distance_fallback(
+ &self,
+ other: &Self,
+ ) -> Result<SquaredDistance, ()> {
+ CalcLengthOrPercentage::compute_squared_distance(
+ &(*self).into(),
+ &(*other).into(),
+ )
}
}
@@ -379,16 +388,6 @@ impl LengthOrPercentage {
}
}
-impl fmt::Debug for LengthOrPercentage {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- LengthOrPercentage::Length(length) => write!(f, "{:?}", length),
- LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage.0 * 100.),
- LengthOrPercentage::Calc(calc) => write!(f, "{:?}", calc),
- }
- }
-}
-
impl ToComputedValue for specified::LengthOrPercentage {
type ComputedValue = LengthOrPercentage;
@@ -426,8 +425,11 @@ impl ToComputedValue for specified::LengthOrPercentage {
}
#[allow(missing_docs)]
+#[animate(fallback = "Self::animate_fallback")]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[derive(Clone, Copy, PartialEq, ToCss)]
+#[css(derive_debug)]
+#[derive(Animate, Clone, ComputeSquaredDistance, Copy, PartialEq, ToCss)]
+#[distance(fallback = "Self::compute_squared_distance_fallback")]
pub enum LengthOrPercentageOrAuto {
Length(Au),
Percentage(Percentage),
@@ -435,20 +437,29 @@ pub enum LengthOrPercentageOrAuto {
Calc(CalcLengthOrPercentage),
}
-impl ComputeSquaredDistance for LengthOrPercentageOrAuto {
- #[inline]
- fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
- match (self, other) {
- (&LengthOrPercentageOrAuto::Length(ref this), &LengthOrPercentageOrAuto::Length(ref other)) => {
- this.compute_squared_distance(other)
- },
- (&LengthOrPercentageOrAuto::Percentage(ref this), &LengthOrPercentageOrAuto::Percentage(ref other)) => {
- this.compute_squared_distance(other)
- },
- (this, other) => {
- <Option<CalcLengthOrPercentage>>::compute_squared_distance(&(*this).into(), &(*other).into())
- }
- }
+impl LengthOrPercentageOrAuto {
+ /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
+ fn animate_fallback(
+ &self,
+ other: &Self,
+ procedure: Procedure,
+ ) -> Result<Self, ()> {
+ let this = <Option<CalcLengthOrPercentage>>::from(*self);
+ let other = <Option<CalcLengthOrPercentage>>::from(*other);
+ Ok(LengthOrPercentageOrAuto::Calc(
+ this.animate(&other, procedure)?.ok_or(())?,
+ ))
+ }
+
+ #[inline]
+ fn compute_squared_distance_fallback(
+ &self,
+ other: &Self,
+ ) -> Result<SquaredDistance, ()> {
+ <Option<CalcLengthOrPercentage>>::compute_squared_distance(
+ &(*self).into(),
+ &(*other).into(),
+ )
}
}
@@ -467,17 +478,6 @@ impl LengthOrPercentageOrAuto {
}
}
-impl fmt::Debug for LengthOrPercentageOrAuto {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- LengthOrPercentageOrAuto::Length(length) => write!(f, "{:?}", length),
- LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage.0 * 100.),
- LengthOrPercentageOrAuto::Auto => write!(f, "auto"),
- LengthOrPercentageOrAuto::Calc(calc) => write!(f, "{:?}", calc),
- }
- }
-}
-
impl ToComputedValue for specified::LengthOrPercentageOrAuto {
type ComputedValue = LengthOrPercentageOrAuto;
@@ -521,8 +521,11 @@ impl ToComputedValue for specified::LengthOrPercentageOrAuto {
}
#[allow(missing_docs)]
+#[animate(fallback = "Self::animate_fallback")]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[derive(Clone, Copy, PartialEq, ToCss)]
+#[css(derive_debug)]
+#[derive(Animate, Clone, ComputeSquaredDistance, Copy, PartialEq, ToCss)]
+#[distance(fallback = "Self::compute_squared_distance_fallback")]
pub enum LengthOrPercentageOrNone {
Length(Au),
Percentage(Percentage),
@@ -530,20 +533,28 @@ pub enum LengthOrPercentageOrNone {
None,
}
-impl ComputeSquaredDistance for LengthOrPercentageOrNone {
- #[inline]
- fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
- match (self, other) {
- (&LengthOrPercentageOrNone::Length(ref this), &LengthOrPercentageOrNone::Length(ref other)) => {
- this.compute_squared_distance(other)
- },
- (&LengthOrPercentageOrNone::Percentage(ref this), &LengthOrPercentageOrNone::Percentage(ref other)) => {
- this.compute_squared_distance(other)
- },
- (this, other) => {
- <Option<CalcLengthOrPercentage>>::compute_squared_distance(&(*this).into(), &(*other).into())
- }
- }
+impl LengthOrPercentageOrNone {
+ /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
+ fn animate_fallback(
+ &self,
+ other: &Self,
+ procedure: Procedure,
+ ) -> Result<Self, ()> {
+ let this = <Option<CalcLengthOrPercentage>>::from(*self);
+ let other = <Option<CalcLengthOrPercentage>>::from(*other);
+ Ok(LengthOrPercentageOrNone::Calc(
+ this.animate(&other, procedure)?.ok_or(())?,
+ ))
+ }
+
+ fn compute_squared_distance_fallback(
+ &self,
+ other: &Self,
+ ) -> Result<SquaredDistance, ()> {
+ <Option<CalcLengthOrPercentage>>::compute_squared_distance(
+ &(*self).into(),
+ &(*other).into(),
+ )
}
}
@@ -559,17 +570,6 @@ impl LengthOrPercentageOrNone {
}
}
-impl fmt::Debug for LengthOrPercentageOrNone {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- LengthOrPercentageOrNone::Length(length) => write!(f, "{:?}", length),
- LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage.0 * 100.),
- LengthOrPercentageOrNone::Calc(calc) => write!(f, "{:?}", calc),
- LengthOrPercentageOrNone::None => write!(f, "none"),
- }
- }
-}
-
impl ToComputedValue for specified::LengthOrPercentageOrNone {
type ComputedValue = LengthOrPercentageOrNone;
@@ -695,28 +695,14 @@ pub type NonNegativeLengthOrNumber = Either<NonNegativeLength, NonNegativeNumber
/// See values/specified/length.rs for more details.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[derive(Clone, Copy, Debug, PartialEq, ToCss)]
+#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq)]
+#[derive(ToAnimatedZero, ToCss)]
pub enum MozLength {
LengthOrPercentageOrAuto(LengthOrPercentageOrAuto),
+ #[animation(error)]
ExtremumLength(ExtremumLength),
}
-impl ComputeSquaredDistance for MozLength {
- #[inline]
- fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
- match (self, other) {
- (&MozLength::LengthOrPercentageOrAuto(ref this), &MozLength::LengthOrPercentageOrAuto(ref other)) => {
- this.compute_squared_distance(other)
- },
- _ => {
- // FIXME(nox): Should this return `Ok(SquaredDistance::Value(1.))`
- // when `self` and `other` are the same extremum value?
- Err(())
- },
- }
- }
-}
-
impl MozLength {
/// Returns the `auto` value.
pub fn auto() -> Self {
@@ -755,28 +741,13 @@ impl ToComputedValue for specified::MozLength {
/// See values/specified/length.rs for more details.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[derive(Clone, Copy, Debug, PartialEq, ToCss)]
+#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToCss)]
pub enum MaxLength {
LengthOrPercentageOrNone(LengthOrPercentageOrNone),
+ #[animation(error)]
ExtremumLength(ExtremumLength),
}
-impl ComputeSquaredDistance for MaxLength {
- #[inline]
- fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
- match (self, other) {
- (&MaxLength::LengthOrPercentageOrNone(ref this), &MaxLength::LengthOrPercentageOrNone(ref other)) => {
- this.compute_squared_distance(other)
- },
- _ => {
- // FIXME(nox): Should this return `Ok(SquaredDistance::Value(1.))`
- // when `self` and `other` are the same extremum value?
- Err(())
- },
- }
- }
-}
-
impl MaxLength {
/// Returns the `none` value.
pub fn none() -> Self {
diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs
index 8a15ef1162c..86aaf29b1c5 100644
--- a/components/style/values/computed/mod.rs
+++ b/components/style/values/computed/mod.rs
@@ -199,6 +199,11 @@ impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> Iterator for ComputedVecIter<
}
/// A trait to represent the conversion between computed and specified values.
+///
+/// This trait is derivable with `#[derive(ToComputedValue)]`. The derived
+/// implementation just calls `ToComputedValue::to_computed_value` on each field
+/// of the passed value, or `Clone::clone` if the field is annotated with
+/// `#[compute(clone)]`.
pub trait ToComputedValue {
/// The computed value type we're going to be converted to.
type ComputedValue;
@@ -327,6 +332,7 @@ impl<T> ToComputedValue for T
impl ComputedValueAsSpecified for Atom {}
impl ComputedValueAsSpecified for bool {}
+impl ComputedValueAsSpecified for f32 {}
impl ComputedValueAsSpecified for specified::BorderStyle {}
diff --git a/components/style/values/distance.rs b/components/style/values/distance.rs
index d4eb91f112f..351f1eb021f 100644
--- a/components/style/values/distance.rs
+++ b/components/style/values/distance.rs
@@ -10,6 +10,17 @@ use std::iter::Sum;
use std::ops::Add;
/// A trait to compute squared distances between two animatable values.
+///
+/// This trait is derivable with `#[derive(ComputeSquaredDistance)]`. The derived
+/// implementation uses a `match` expression with identical patterns for both
+/// `self` and `other`, calling `ComputeSquaredDistance::compute_squared_distance`
+/// on each fields of the values.
+///
+/// If a variant is annotated with `#[animation(error)]`, the corresponding
+/// `match` arm is not generated.
+///
+/// If the two values are not similar, an error is returned unless a fallback
+/// function has been specified through `#[distance(fallback)]`.
pub trait ComputeSquaredDistance {
/// Computes the squared distance between two animatable values.
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>;
diff --git a/components/style/values/generics/background.rs b/components/style/values/generics/background.rs
index 8a79691f3b9..abcfb655eec 100644
--- a/components/style/values/generics/background.rs
+++ b/components/style/values/generics/background.rs
@@ -5,8 +5,9 @@
//! Generic types for CSS values related to backgrounds.
/// A generic value for the `background-size` property.
-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug)]
+#[derive(HasViewportPercentage, PartialEq, ToComputedValue, ToCss)]
pub enum BackgroundSize<LengthOrPercentageOrAuto> {
/// `<width> <height>`
Explicit {
@@ -16,8 +17,10 @@ pub enum BackgroundSize<LengthOrPercentageOrAuto> {
height: LengthOrPercentageOrAuto
},
/// `cover`
+ #[animation(error)]
Cover,
/// `contain`
+ #[animation(error)]
Contain,
}
diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs
index 99de026d706..019ed6599e2 100644
--- a/components/style/values/generics/basic_shape.rs
+++ b/components/style/values/generics/basic_shape.rs
@@ -44,11 +44,18 @@ add_impls_for_keyword_enum!(ShapeBox);
/// A shape source, for some reference box.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[derive(Clone, Debug, PartialEq, ToComputedValue, ToCss)]
+#[derive(Animate, Clone, Debug, PartialEq, ToComputedValue, ToCss)]
pub enum ShapeSource<BasicShape, ReferenceBox, Url> {
+ #[animation(error)]
Url(Url),
- Shape(BasicShape, Option<ReferenceBox>),
+ Shape(
+ BasicShape,
+ #[animation(constant)]
+ Option<ReferenceBox>,
+ ),
+ #[animation(error)]
Box(ReferenceBox),
+ #[animation(error)]
None,
}
@@ -94,10 +101,13 @@ pub struct Ellipse<H, V, LengthOrPercentage> {
/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToComputedValue, ToCss)]
+#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq)]
+#[derive(ToComputedValue, ToCss)]
pub enum ShapeRadius<LengthOrPercentage> {
Length(LengthOrPercentage),
+ #[animation(error)]
ClosestSide,
+ #[animation(error)]
FarthestSide,
}
@@ -123,29 +133,6 @@ define_css_keyword_enum!(FillRule:
);
add_impls_for_keyword_enum!(FillRule);
-// FIXME(nox): This should be derivable, but we need to implement Animate
-// on the T types.
-impl<B, T, U> Animate for ShapeSource<B, T, U>
-where
- B: Animate,
- T: Clone + PartialEq,
-{
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- match (self, other) {
- (
- &ShapeSource::Shape(ref this, ref this_box),
- &ShapeSource::Shape(ref other, ref other_box),
- ) if this_box == other_box => {
- Ok(ShapeSource::Shape(
- this.animate(other, procedure)?,
- this_box.clone(),
- ))
- },
- _ => Err(()),
- }
- }
-}
-
// FIXME(nox): Implement ComputeSquaredDistance for T types and stop
// using PartialEq here, this will let us derive this impl.
impl<B, T, U> ComputeSquaredDistance for ShapeSource<B, T, U>
@@ -191,20 +178,6 @@ impl<L> ToCss for InsetRect<L>
}
}
-impl<L> Animate for ShapeRadius<L>
-where
- L: Animate,
-{
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- match (self, other) {
- (&ShapeRadius::Length(ref this), &ShapeRadius::Length(ref other)) => {
- Ok(ShapeRadius::Length(this.animate(other, procedure)?))
- },
- _ => Err(()),
- }
- }
-}
-
impl<L> Default for ShapeRadius<L> {
#[inline]
fn default() -> Self { ShapeRadius::ClosestSide }
diff --git a/components/style/values/generics/effects.rs b/components/style/values/generics/effects.rs
index 3004c21f9b2..5d95ae19a8f 100644
--- a/components/style/values/generics/effects.rs
+++ b/components/style/values/generics/effects.rs
@@ -11,13 +11,15 @@ use values::specified::url::SpecifiedUrl;
/// A generic value for a single `box-shadow`.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)]
+#[derive(Animate, Clone, Debug, HasViewportPercentage, PartialEq)]
+#[derive(ToAnimatedValue, ToAnimatedZero)]
pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
/// The base shadow.
pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>,
/// The spread radius.
pub spread: ShapeLength,
/// Whether this is an inset box shadow.
+ #[animation(constant)]
pub inset: bool,
}
diff --git a/components/style/values/generics/grid.rs b/components/style/values/generics/grid.rs
index 91b1e922d14..87f427f6cb3 100644
--- a/components/style/values/generics/grid.rs
+++ b/components/style/values/generics/grid.rs
@@ -10,7 +10,7 @@ use parser::{Parse, ParserContext};
use std::{fmt, mem, usize};
use style_traits::{ToCss, ParseError, StyleParseError};
use values::{CSSFloat, CustomIdent, serialize_dimension};
-use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
+use values::computed::ComputedValueAsSpecified;
use values::specified::Integer;
use values::specified::grid::parse_line_names;
@@ -137,13 +137,14 @@ define_css_keyword_enum!{ TrackKeyword:
"max-content" => MaxContent,
"min-content" => MinContent
}
+impl ComputedValueAsSpecified for TrackKeyword {}
-#[derive(Clone, Debug, PartialEq)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A track breadth for explicit grid track sizing. It's generic solely to
/// avoid re-implementing it for the computed type.
///
/// https://drafts.csswg.org/css-grid/#typedef-track-breadth
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Clone, Debug, PartialEq, ToComputedValue)]
pub enum TrackBreadth<L> {
/// The generic type is almost always a non-negative `<length-percentage>`
Breadth(L),
@@ -176,35 +177,12 @@ impl<L: ToCss> ToCss for TrackBreadth<L> {
}
}
-impl<L: ToComputedValue> ToComputedValue for TrackBreadth<L> {
- type ComputedValue = TrackBreadth<L::ComputedValue>;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
- match *self {
- TrackBreadth::Breadth(ref lop) => TrackBreadth::Breadth(lop.to_computed_value(context)),
- TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr),
- TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k),
- }
- }
-
- #[inline]
- fn from_computed_value(computed: &Self::ComputedValue) -> Self {
- match *computed {
- TrackBreadth::Breadth(ref lop) =>
- TrackBreadth::Breadth(ToComputedValue::from_computed_value(lop)),
- TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr),
- TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k),
- }
- }
-}
-
/// A `<track-size>` type for explicit grid track sizing. Like `<track-breadth>`, this is
/// generic only to avoid code bloat. It only takes `<length-percentage>`
///
/// https://drafts.csswg.org/css-grid/#typedef-track-size
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
+#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
pub enum TrackSize<L> {
/// A flexible `<track-breadth>`
Breadth(TrackBreadth<L>),
@@ -286,39 +264,6 @@ impl<L: ToCss> ToCss for TrackSize<L> {
}
}
-impl<L: ToComputedValue> ToComputedValue for TrackSize<L> {
- type ComputedValue = TrackSize<L::ComputedValue>;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
- match *self {
- TrackSize::Breadth(ref b) => match *b {
- // <flex> outside `minmax()` expands to `mimmax(auto, <flex>)`
- // https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-flex
- TrackBreadth::Flex(f) =>
- TrackSize::Minmax(TrackBreadth::Keyword(TrackKeyword::Auto), TrackBreadth::Flex(f)),
- _ => TrackSize::Breadth(b.to_computed_value(context)),
- },
- TrackSize::Minmax(ref b_1, ref b_2) =>
- TrackSize::Minmax(b_1.to_computed_value(context), b_2.to_computed_value(context)),
- TrackSize::FitContent(ref lop) => TrackSize::FitContent(lop.to_computed_value(context)),
- }
- }
-
- #[inline]
- fn from_computed_value(computed: &Self::ComputedValue) -> Self {
- match *computed {
- TrackSize::Breadth(ref b) =>
- TrackSize::Breadth(ToComputedValue::from_computed_value(b)),
- TrackSize::Minmax(ref b_1, ref b_2) =>
- TrackSize::Minmax(ToComputedValue::from_computed_value(b_1),
- ToComputedValue::from_computed_value(b_2)),
- TrackSize::FitContent(ref lop) =>
- TrackSize::FitContent(ToComputedValue::from_computed_value(lop)),
- }
- }
-}
-
/// Helper function for serializing identifiers with a prefix and suffix, used
/// for serializing <line-names> (in grid).
pub fn concat_serialize_idents<W>(prefix: &str, suffix: &str,
@@ -382,8 +327,8 @@ no_viewport_percentage!(RepeatCount);
///
/// It can also hold `repeat()` function parameters, which expands into the respective
/// values in its computed form.
-#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Clone, Debug, PartialEq, ToComputedValue)]
pub struct TrackRepeat<L> {
/// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`)
pub count: RepeatCount,
@@ -392,6 +337,7 @@ pub struct TrackRepeat<L> {
/// If there's no `<line-names>`, then it's represented by an empty vector.
/// For N `<track-size>` values, there will be N+1 `<line-names>`, and so this vector's
/// length is always one value more than that of the `<track-size>`.
+ #[compute(clone)]
pub line_names: Box<[Box<[CustomIdent]>]>,
/// `<track-size>` values.
pub track_sizes: Vec<TrackSize<L>>,
@@ -479,31 +425,6 @@ impl<L: Clone> TrackRepeat<L> {
}
}
}
-impl<L: ToComputedValue> ToComputedValue for TrackRepeat<L> {
- type ComputedValue = TrackRepeat<L::ComputedValue>;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
- TrackRepeat {
- count: self.count,
- track_sizes: self.track_sizes.iter()
- .map(|val| val.to_computed_value(context))
- .collect(),
- line_names: self.line_names.clone(),
- }
- }
-
- #[inline]
- fn from_computed_value(computed: &Self::ComputedValue) -> Self {
- TrackRepeat {
- count: computed.count,
- track_sizes: computed.track_sizes.iter()
- .map(ToComputedValue::from_computed_value)
- .collect(),
- line_names: computed.line_names.clone(),
- }
- }
-}
/// The type of a `<track-list>` as determined during parsing.
///
@@ -533,8 +454,8 @@ impl ComputedValueAsSpecified for TrackListType {}
/// A grid `<track-list>` type.
///
/// https://drafts.csswg.org/css-grid/#typedef-track-list
-#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Clone, Debug, PartialEq, ToComputedValue)]
pub struct TrackList<T> {
/// The type of this `<track-list>` (auto, explicit or general).
///
@@ -548,6 +469,7 @@ pub struct TrackList<T> {
/// If there's no `<line-names>`, then it's represented by an empty vector.
/// For N values, there will be N+1 `<line-names>`, and so this vector's
/// length is always one value more than that of the `<track-size>`.
+ #[compute(clone)]
pub line_names: Box<[Box<[CustomIdent]>]>,
/// `<auto-repeat>` value. There can only be one `<auto-repeat>` in a TrackList.
pub auto_repeat: Option<TrackRepeat<T>>,
@@ -698,8 +620,8 @@ no_viewport_percentage!(LineNameList);
/// Variants for `<grid-template-rows> | <grid-template-columns>`
/// Subgrid deferred to Level 2 spec due to lack of implementation.
/// But it's implemented in gecko, so we have to as well.
-#[derive(Clone, Debug, PartialEq, ToCss)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Clone, Debug, PartialEq, ToComputedValue, ToCss)]
pub enum GridTemplateComponent<L> {
/// `none` value.
None,
diff --git a/components/style/values/generics/image.rs b/components/style/values/generics/image.rs
index 867364e3df3..3e977759d70 100644
--- a/components/style/values/generics/image.rs
+++ b/components/style/values/generics/image.rs
@@ -35,16 +35,18 @@ pub enum Image<Gradient, MozImageRect, ImageUrl> {
/// A CSS gradient.
/// https://drafts.csswg.org/css-images/#gradients
-#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
pub struct Gradient<LineDirection, Length, LengthOrPercentage, Position, Color, Angle> {
/// Gradients can be linear or radial.
pub kind: GradientKind<LineDirection, Length, LengthOrPercentage, Position, Angle>,
/// The color stops and interpolation hints.
pub items: Vec<GradientItem<Color, LengthOrPercentage>>,
/// True if this is a repeating gradient.
+ #[compute(clone)]
pub repeating: bool,
/// Compatibility mode.
+ #[compute(clone)]
pub compat_mode: CompatMode,
}
@@ -61,8 +63,8 @@ pub enum CompatMode {
}
/// A gradient kind.
-#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
pub enum GradientKind<LineDirection, Length, LengthOrPercentage, Position, Angle> {
/// A linear gradient.
Linear(LineDirection),
diff --git a/components/style/values/generics/svg.rs b/components/style/values/generics/svg.rs
index bc3cb5fda18..87b0a74bc23 100644
--- a/components/style/values/generics/svg.rs
+++ b/components/style/values/generics/svg.rs
@@ -16,7 +16,8 @@ use values::distance::{ComputeSquaredDistance, SquaredDistance};
///
/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)]
+#[derive(Animate, Clone, ComputeSquaredDistance, Debug, PartialEq)]
+#[derive(ToAnimatedValue, ToComputedValue, ToCss)]
pub struct SVGPaint<ColorType, UrlPaintServer> {
/// The paint source
pub kind: SVGPaintKind<ColorType, UrlPaintServer>,
@@ -30,13 +31,15 @@ pub struct SVGPaint<ColorType, UrlPaintServer> {
/// to have a fallback, Gecko lets the context
/// properties have a fallback as well.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-#[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)]
+#[derive(Animate, Clone, ComputeSquaredDistance, Debug, PartialEq)]
+#[derive(ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)]
pub enum SVGPaintKind<ColorType, UrlPaintServer> {
/// `none`
None,
/// `<color>`
Color(ColorType),
/// `url(...)`
+ #[animation(error)]
PaintServer(UrlPaintServer),
/// `context-fill`
ContextFill,
diff --git a/components/style/values/specified/grid.rs b/components/style/values/specified/grid.rs
index 92a442a1cf0..72ce404d25c 100644
--- a/components/style/values/specified/grid.rs
+++ b/components/style/values/specified/grid.rs
@@ -11,7 +11,6 @@ use std::ascii::AsciiExt;
use std::mem;
use style_traits::{HasViewportPercentage, ParseError, StyleParseError};
use values::{CSSFloat, CustomIdent};
-use values::computed::{self, Context, ToComputedValue};
use values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth, TrackKeyword, TrackRepeat};
use values::generics::grid::{LineNameList, TrackSize, TrackList, TrackListType};
use values::specified::LengthOrPercentage;
@@ -286,42 +285,6 @@ impl HasViewportPercentage for TrackList<LengthOrPercentage> {
}
}
-
-impl ToComputedValue for TrackList<LengthOrPercentage> {
- type ComputedValue = TrackList<computed::LengthOrPercentage>;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
- let mut values = Vec::with_capacity(self.values.len() + 1);
- for value in self.values.iter().map(|val| val.to_computed_value(context)) {
- values.push(value);
- }
-
- TrackList {
- list_type: self.list_type.to_computed_value(context),
- values: values,
- line_names: self.line_names.clone(),
- auto_repeat: self.auto_repeat.clone().map(|repeat| repeat.to_computed_value(context)),
- }
- }
-
- #[inline]
- fn from_computed_value(computed: &Self::ComputedValue) -> Self {
- let mut values = Vec::with_capacity(computed.values.len() + 1);
- for value in computed.values.iter().map(ToComputedValue::from_computed_value) {
- values.push(value);
- }
-
- TrackList {
- list_type: computed.list_type,
- values: values,
- line_names: computed.line_names.clone(),
- auto_repeat: computed.auto_repeat.clone().map(|ref repeat| TrackRepeat::from_computed_value(repeat)),
- }
- }
-}
-
-
impl Parse for GridTemplateComponent<LengthOrPercentage> {
// FIXME: Derive Parse (probably with None_)
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
@@ -354,27 +317,3 @@ impl HasViewportPercentage for GridTemplateComponent<LengthOrPercentage> {
}
}
}
-
-impl ToComputedValue for GridTemplateComponent<LengthOrPercentage> {
- type ComputedValue = GridTemplateComponent<computed::LengthOrPercentage>;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
- match *self {
- GridTemplateComponent::None => GridTemplateComponent::None,
- GridTemplateComponent::TrackList(ref l) => GridTemplateComponent::TrackList(l.to_computed_value(context)),
- GridTemplateComponent::Subgrid(ref n) => GridTemplateComponent::Subgrid(n.to_computed_value(context)),
- }
- }
-
- #[inline]
- fn from_computed_value(computed: &Self::ComputedValue) -> Self {
- match *computed {
- GridTemplateComponent::None => GridTemplateComponent::None,
- GridTemplateComponent::TrackList(ref l) =>
- GridTemplateComponent::TrackList(ToComputedValue::from_computed_value(l)),
- GridTemplateComponent::Subgrid(ref n) =>
- GridTemplateComponent::Subgrid(ToComputedValue::from_computed_value(n)),
- }
- }
-}
diff --git a/components/style_derive/animate.rs b/components/style_derive/animate.rs
index 94d14336087..d4fe5c94a53 100644
--- a/components/style_derive/animate.rs
+++ b/components/style_derive/animate.rs
@@ -3,21 +3,22 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use cg;
-use quote;
-use syn;
+use quote::Tokens;
+use syn::{DeriveInput, Path};
-pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
+pub fn derive(input: DeriveInput) -> Tokens {
let name = &input.ident;
let trait_path = &["values", "animated", "Animate"];
let (impl_generics, ty_generics, mut where_clause) =
cg::trait_parts(&input, trait_path);
+ let input_attrs = cg::parse_input_attrs::<AnimateInputAttrs>(&input);
let variants = cg::variants(&input);
let mut match_body = quote!();
let mut append_error_clause = variants.len() > 1;
match_body.append_all(variants.iter().flat_map(|variant| {
- let attrs = cg::parse_variant_attrs::<AnimateAttrs>(variant);
- if attrs.error {
+ let variant_attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(variant);
+ if variant_attrs.error {
append_error_clause = true;
return None;
}
@@ -28,11 +29,32 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let mut computations = quote!();
let iter = result_info.iter().zip(this_info.iter().zip(&other_info));
computations.append_all(iter.map(|(result, (this, other))| {
- where_clause.predicates.push(
- cg::where_predicate(this.field.ty.clone(), trait_path),
- );
- quote! {
- let #result = ::values::animated::Animate::animate(#this, #other, procedure)?;
+ let field_attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&result.field);
+ if field_attrs.constant {
+ if cg::is_parameterized(&result.field.ty, where_clause.params, None) {
+ where_clause.inner.predicates.push(cg::where_predicate(
+ result.field.ty.clone(),
+ &["std", "cmp", "PartialEq"],
+ None,
+ ));
+ where_clause.inner.predicates.push(cg::where_predicate(
+ result.field.ty.clone(),
+ &["std", "clone", "Clone"],
+ None,
+ ));
+ }
+ quote! {
+ if #this != #other {
+ return Err(());
+ }
+ let #result = ::std::clone::Clone::clone(#this);
+ }
+ } else {
+ where_clause.add_trait_bound(&result.field.ty);
+ quote! {
+ let #result =
+ ::values::animated::Animate::animate(#this, #other, procedure)?;
+ }
}
}));
Some(quote! {
@@ -44,7 +66,13 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
}));
if append_error_clause {
- match_body = quote! { #match_body, _ => Err(()), };
+ if let Some(fallback) = input_attrs.fallback {
+ match_body.append(quote! {
+ (this, other) => #fallback(this, other, procedure)
+ });
+ } else {
+ match_body.append(quote! { _ => Err(()) });
+ }
}
quote! {
@@ -64,8 +92,20 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
}
}
-#[derive(Default, FromVariant)]
#[darling(attributes(animate), default)]
-pub struct AnimateAttrs {
+#[derive(Default, FromDeriveInput)]
+struct AnimateInputAttrs {
+ fallback: Option<Path>,
+}
+
+#[darling(attributes(animation), default)]
+#[derive(Default, FromVariant)]
+pub struct AnimationVariantAttrs {
pub error: bool,
}
+
+#[darling(attributes(animation), default)]
+#[derive(Default, FromField)]
+pub struct AnimationFieldAttrs {
+ pub constant: bool,
+}
diff --git a/components/style_derive/cg.rs b/components/style_derive/cg.rs
index b670da16737..6937d5836d2 100644
--- a/components/style_derive/cg.rs
+++ b/components/style_derive/cg.rs
@@ -2,17 +2,86 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use darling::FromVariant;
-use quote::Tokens;
+use darling::{FromDeriveInput, FromField, FromVariant};
+use quote::{ToTokens, Tokens};
use std::borrow::Cow;
+use std::collections::HashSet;
use std::iter;
-use syn::{AngleBracketedParameterData, Body, DeriveInput, Ident, ImplGenerics};
-use syn::{Path, PathParameters, PathSegment, PolyTraitRef, QSelf};
-use syn::{TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound, TypeBinding};
-use syn::{Variant, WhereBoundPredicate, WhereClause, WherePredicate};
+use syn::{self, AngleBracketedParameterData, Body, DeriveInput, Field, Ident};
+use syn::{ImplGenerics, Path, PathParameters, PathSegment, PolyTraitRef};
+use syn::{QSelf, TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound};
+use syn::{TypeBinding, Variant, WhereBoundPredicate, WherePredicate};
use syn::visit::{self, Visitor};
use synstructure::{self, BindOpts, BindStyle, BindingInfo};
+pub struct WhereClause<'input, 'path> {
+ pub inner: syn::WhereClause,
+ pub params: &'input [TyParam],
+ trait_path: &'path [&'path str],
+ trait_output: Option<&'path str>,
+ bounded_types: HashSet<Ty>,
+}
+
+impl<'input, 'path> ToTokens for WhereClause<'input, 'path> {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ self.inner.to_tokens(tokens);
+ }
+}
+
+impl<'input, 'path> WhereClause<'input, 'path> {
+ pub fn add_trait_bound(&mut self, ty: &Ty) {
+ let trait_path = self.trait_path;
+ let params = self.params;
+ let mut found = self.trait_output.map(|_| HashSet::new());
+ if self.bounded_types.contains(&ty) {
+ return;
+ }
+ if !is_parameterized(&ty, params, found.as_mut()) {
+ return;
+ }
+ self.bounded_types.insert(ty.clone());
+
+ let output = if let Some(output) = self.trait_output {
+ output
+ } else {
+ self.inner.predicates.push(where_predicate(ty.clone(), trait_path, None));
+ return;
+ };
+
+ if let Ty::Path(None, ref path) = *ty {
+ if path_to_ident(path).is_some() {
+ self.inner.predicates.push(where_predicate(ty.clone(), trait_path, None));
+ return;
+ }
+ }
+
+ let output_type = map_type_params(ty, params, &mut |ident| {
+ let ty = Ty::Path(None, ident.clone().into());
+ fmap_output_type(ty, trait_path, output)
+ });
+
+ let pred = where_predicate(
+ ty.clone(),
+ trait_path,
+ Some((output, output_type)),
+ );
+
+ self.inner.predicates.push(pred);
+
+ if let Some(found) = found {
+ for ident in found {
+ let ty = Ty::Path(None, ident.into());
+ if !self.bounded_types.contains(&ty) {
+ self.bounded_types.insert(ty.clone());
+ self.inner.predicates.push(
+ where_predicate(ty, trait_path, None),
+ );
+ };
+ }
+ }
+ }
+}
+
pub fn fmap_match<F>(
input: &DeriveInput,
bind_style: BindStyle,
@@ -35,23 +104,36 @@ where
})
}
-pub fn fmap_trait_parts<'a>(
- input: &'a DeriveInput,
+fn fmap_output_type(
+ ty: Ty,
trait_path: &[&str],
trait_output: &str,
-) -> (ImplGenerics<'a>, TyGenerics<'a>, WhereClause, Path) {
- let (impl_generics, ty_generics, where_clause) = trait_parts(input, trait_path);
+) -> Ty {
+ Ty::Path(
+ Some(QSelf {
+ ty: Box::new(ty),
+ position: trait_path.len(),
+ }),
+ path(trait_path.iter().chain(iter::once(&trait_output))),
+ )
+}
+
+pub fn fmap_trait_parts<'input, 'path>(
+ input: &'input DeriveInput,
+ trait_path: &'path [&'path str],
+ trait_output: &'path str,
+) -> (ImplGenerics<'input>, TyGenerics<'input>, WhereClause<'input, 'path>, Path) {
+ let (impl_generics, ty_generics, mut where_clause) = trait_parts(input, trait_path);
+ where_clause.trait_output = Some(trait_output);
let output_ty = PathSegment {
ident: input.ident.clone(),
parameters: PathParameters::AngleBracketed(AngleBracketedParameterData {
lifetimes: input.generics.lifetimes.iter().map(|l| l.lifetime.clone()).collect(),
types: input.generics.ty_params.iter().map(|ty| {
- Ty::Path(
- Some(QSelf {
- ty: Box::new(Ty::Path(None, ty.ident.clone().into())),
- position: trait_path.len(),
- }),
- path(trait_path.iter().chain(iter::once(&trait_output))),
+ fmap_output_type(
+ Ty::Path(None, ty.ident.clone().into()),
+ trait_path,
+ trait_output,
)
}).collect(),
.. Default::default()
@@ -60,72 +142,106 @@ pub fn fmap_trait_parts<'a>(
(impl_generics, ty_generics, where_clause, output_ty)
}
-fn fmap_trait_where_predicate(
- bounded_ty: Ty,
- trait_path: &[&str],
- trait_output: Option<(&str, Ty)>,
-) -> WherePredicate {
- WherePredicate::BoundPredicate(WhereBoundPredicate {
- bound_lifetimes: vec![],
- bounded_ty,
- bounds: vec![TyParamBound::Trait(
- PolyTraitRef {
- bound_lifetimes: vec![],
- trait_ref: fmap_trait_ref(trait_path, trait_output),
- },
- TraitBoundModifier::None
- )],
- })
-}
-
-fn fmap_trait_ref(path: &[&str], output: Option<(&str, Ty)>) -> Path {
- let (name, parent) = path.split_last().unwrap();
- let last_segment = PathSegment {
- ident: (*name).into(),
- parameters: PathParameters::AngleBracketed(
- AngleBracketedParameterData {
- bindings: output.into_iter().map(|(param, ty)| {
- TypeBinding { ident: param.into(), ty }
- }).collect(),
- .. Default::default()
- }
- )
- };
- Path {
- global: true,
- segments: {
- parent
- .iter()
- .cloned()
- .map(Into::into)
- .chain(iter::once(last_segment))
- .collect()
- },
- }
-}
-
-pub fn is_parameterized(ty: &Ty, params: &[TyParam]) -> bool {
- struct IsParameterized<'a> {
+pub fn is_parameterized(
+ ty: &Ty,
+ params: &[TyParam],
+ found: Option<&mut HashSet<Ident>>,
+) -> bool {
+ struct IsParameterized<'a, 'b> {
params: &'a [TyParam],
has_free: bool,
+ found: Option<&'b mut HashSet<Ident>>,
}
- impl<'a> Visitor for IsParameterized<'a> {
+ impl<'a, 'b> Visitor for IsParameterized<'a, 'b> {
fn visit_path(&mut self, path: &Path) {
- if !path.global && path.segments.len() == 1 {
- if self.params.iter().any(|param| param.ident == path.segments[0].ident) {
+ if let Some(ident) = path_to_ident(path) {
+ if self.params.iter().any(|param| param.ident == ident) {
self.has_free = true;
+ if let Some(ref mut found) = self.found {
+ found.insert(ident.clone());
+ }
}
}
visit::walk_path(self, path);
}
}
- let mut visitor = IsParameterized { params: params, has_free: false };
+ let mut visitor = IsParameterized { params, has_free: false, found };
visitor.visit_ty(ty);
visitor.has_free
}
+pub fn map_type_params<F>(ty: &Ty, params: &[TyParam], f: &mut F) -> Ty
+where
+ F: FnMut(&Ident) -> Ty,
+{
+ match *ty {
+ Ty::Slice(ref ty) => Ty::Slice(Box::new(map_type_params(ty, params, f))),
+ Ty::Array(ref ty, ref expr) => {
+ Ty::Array(Box::new(map_type_params(ty, params, f)), expr.clone())
+ },
+ Ty::Never => Ty::Never,
+ Ty::Tup(ref items) => {
+ Ty::Tup(items.iter().map(|ty| map_type_params(ty, params, f)).collect())
+ },
+ Ty::Path(None, ref path) => {
+ if let Some(ident) = path_to_ident(path) {
+ if params.iter().any(|param| param.ident == ident) {
+ return f(ident);
+ }
+ }
+ Ty::Path(None, map_type_params_in_path(path, params, f))
+ }
+ Ty::Path(ref qself, ref path) => {
+ Ty::Path(
+ qself.as_ref().map(|qself| {
+ QSelf {
+ ty: Box::new(map_type_params(&qself.ty, params, f)),
+ position: qself.position,
+ }
+ }),
+ map_type_params_in_path(path, params, f),
+ )
+ },
+ Ty::Paren(ref ty) => Ty::Paren(Box::new(map_type_params(ty, params, f))),
+ ref ty => panic!("type {:?} cannot be mapped yet", ty),
+ }
+}
+
+fn map_type_params_in_path<F>(path: &Path, params: &[TyParam], f: &mut F) -> Path
+where
+ F: FnMut(&Ident) -> Ty,
+{
+ Path {
+ global: path.global,
+ segments: path.segments.iter().map(|segment| {
+ PathSegment {
+ ident: segment.ident.clone(),
+ parameters: match segment.parameters {
+ PathParameters::AngleBracketed(ref data) => {
+ PathParameters::AngleBracketed(AngleBracketedParameterData {
+ lifetimes: data.lifetimes.clone(),
+ types: data.types.iter().map(|ty| {
+ map_type_params(ty, params, f)
+ }).collect(),
+ bindings: data.bindings.iter().map(|binding| {
+ TypeBinding {
+ ident: binding.ident.clone(),
+ ty: map_type_params(&binding.ty, params, f),
+ }
+ }).collect(),
+ })
+ },
+ ref parameters => {
+ panic!("parameters {:?} cannot be mapped yet", parameters)
+ },
+ },
+ }
+ }).collect(),
+ }
+}
+
pub fn path<S>(segments: S) -> Path
where
S: IntoIterator,
@@ -137,13 +253,46 @@ where
}
}
+fn path_to_ident(path: &Path) -> Option<&Ident> {
+ match *path {
+ Path { global: false, ref segments } if segments.len() == 1 => {
+ if segments[0].parameters.is_empty() {
+ Some(&segments[0].ident)
+ } else {
+ None
+ }
+ },
+ _ => None,
+ }
+}
+
+pub fn parse_field_attrs<A>(field: &Field) -> A
+where
+ A: FromField,
+{
+ match A::from_field(field) {
+ Ok(attrs) => attrs,
+ Err(e) => panic!("failed to parse field attributes: {}", e),
+ }
+}
+
+pub fn parse_input_attrs<A>(input: &DeriveInput) -> A
+where
+ A: FromDeriveInput,
+{
+ match A::from_derive_input(input) {
+ Ok(attrs) => attrs,
+ Err(e) => panic!("failed to parse input attributes: {}", e),
+ }
+}
+
pub fn parse_variant_attrs<A>(variant: &Variant) -> A
where
A: FromVariant,
{
match A::from_variant(variant) {
Ok(attrs) => attrs,
- Err(e) => panic!("failed to parse attributes: {}", e),
+ Err(e) => panic!("failed to parse variant attributes: {}", e),
}
}
@@ -159,22 +308,47 @@ pub fn ref_pattern<'a>(
)
}
-pub fn trait_parts<'a>(
- input: &'a DeriveInput,
- trait_path: &[&str],
-) -> (ImplGenerics<'a>, TyGenerics<'a>, WhereClause) {
+pub fn trait_parts<'input, 'path>(
+ input: &'input DeriveInput,
+ trait_path: &'path [&'path str],
+) -> (ImplGenerics<'input>, TyGenerics<'input>, WhereClause<'input, 'path>) {
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
- let mut where_clause = where_clause.clone();
- for param in &input.generics.ty_params {
- where_clause.predicates.push(fmap_trait_where_predicate(
- Ty::Path(None, param.ident.clone().into()),
- trait_path,
- None,
- ));
- }
+ let where_clause = WhereClause {
+ inner: where_clause.clone(),
+ params: &input.generics.ty_params,
+ trait_path,
+ trait_output: None,
+ bounded_types: HashSet::new()
+ };
(impl_generics, ty_generics, where_clause)
}
+fn trait_ref(path: &[&str], output: Option<(&str, Ty)>) -> Path {
+ let (name, parent) = path.split_last().unwrap();
+ let last_segment = PathSegment {
+ ident: (*name).into(),
+ parameters: PathParameters::AngleBracketed(
+ AngleBracketedParameterData {
+ bindings: output.into_iter().map(|(param, ty)| {
+ TypeBinding { ident: param.into(), ty }
+ }).collect(),
+ .. Default::default()
+ }
+ )
+ };
+ Path {
+ global: true,
+ segments: {
+ parent
+ .iter()
+ .cloned()
+ .map(Into::into)
+ .chain(iter::once(last_segment))
+ .collect()
+ },
+ }
+}
+
pub fn value<'a>(
name: &Ident,
variant: &'a Variant,
@@ -215,16 +389,20 @@ pub fn variants(input: &DeriveInput) -> Cow<[Variant]> {
}
}
-pub fn where_predicate(ty: Ty, segments: &[&str]) -> WherePredicate {
+pub fn where_predicate(
+ bounded_ty: Ty,
+ trait_path: &[&str],
+ trait_output: Option<(&str, Ty)>,
+) -> WherePredicate {
WherePredicate::BoundPredicate(WhereBoundPredicate {
bound_lifetimes: vec![],
- bounded_ty: ty,
+ bounded_ty,
bounds: vec![TyParamBound::Trait(
PolyTraitRef {
bound_lifetimes: vec![],
- trait_ref: path(segments),
+ trait_ref: trait_ref(trait_path, trait_output),
},
- TraitBoundModifier::None,
+ TraitBoundModifier::None
)],
})
}
diff --git a/components/style_derive/compute_squared_distance.rs b/components/style_derive/compute_squared_distance.rs
index 860e568ea88..cbdd9c62acc 100644
--- a/components/style_derive/compute_squared_distance.rs
+++ b/components/style_derive/compute_squared_distance.rs
@@ -2,22 +2,23 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use animate::AnimateAttrs;
+use animate::AnimationVariantAttrs;
use cg;
-use quote;
-use syn;
+use quote::Tokens;
+use syn::{DeriveInput, Path};
-pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
+pub fn derive(input: DeriveInput) -> Tokens {
let name = &input.ident;
let trait_path = &["values", "distance", "ComputeSquaredDistance"];
let (impl_generics, ty_generics, mut where_clause) =
cg::trait_parts(&input, trait_path);
+ let input_attrs = cg::parse_input_attrs::<DistanceInputAttrs>(&input);
let variants = cg::variants(&input);
let mut match_body = quote!();
let mut append_error_clause = variants.len() > 1;
match_body.append_all(variants.iter().map(|variant| {
- let attrs = cg::parse_variant_attrs::<AnimateAttrs>(variant);
+ let attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(variant);
if attrs.error {
append_error_clause = true;
return None;
@@ -30,9 +31,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
} else {
let mut sum = quote!();
sum.append_separated(this_info.iter().zip(&other_info).map(|(this, other)| {
- where_clause.predicates.push(
- cg::where_predicate(this.field.ty.clone(), trait_path),
- );
+ where_clause.add_trait_bound(&this.field.ty);
quote! {
::values::distance::ComputeSquaredDistance::compute_squared_distance(#this, #other)?
}
@@ -47,7 +46,13 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
}));
if append_error_clause {
- match_body = quote! { #match_body, _ => Err(()), };
+ if let Some(fallback) = input_attrs.fallback {
+ match_body.append(quote! {
+ (this, other) => #fallback(this, other)
+ });
+ } else {
+ match_body.append(quote! { _ => Err(()) });
+ }
}
quote! {
@@ -65,3 +70,9 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
}
}
}
+
+#[darling(attributes(distance), default)]
+#[derive(Default, FromDeriveInput)]
+struct DistanceInputAttrs {
+ fallback: Option<Path>,
+}
diff --git a/components/style_derive/has_viewport_percentage.rs b/components/style_derive/has_viewport_percentage.rs
index 5f26d988b8a..18856576fb8 100644
--- a/components/style_derive/has_viewport_percentage.rs
+++ b/components/style_derive/has_viewport_percentage.rs
@@ -19,11 +19,10 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
None => return Some(quote!(false)),
Some(pair) => pair,
};
+ where_clause.add_trait_bound(&first.field.ty);
let mut expr = quote!(::style_traits::HasViewportPercentage::has_viewport_percentage(#first));
for binding in rest {
- where_clause.predicates.push(
- cg::where_predicate(binding.field.ty.clone(), trait_path),
- );
+ where_clause.add_trait_bound(&binding.field.ty);
expr = quote!(#expr || ::style_traits::HasViewportPercentage::has_viewport_percentage(#binding));
}
Some(expr)
diff --git a/components/style_derive/lib.rs b/components/style_derive/lib.rs
index e589759f813..f98829e60bf 100644
--- a/components/style_derive/lib.rs
+++ b/components/style_derive/lib.rs
@@ -19,13 +19,13 @@ mod to_animated_zero;
mod to_computed_value;
mod to_css;
-#[proc_macro_derive(Animate, attributes(animation))]
+#[proc_macro_derive(Animate, attributes(animate, animation))]
pub fn derive_animate(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
animate::derive(input).to_string().parse().unwrap()
}
-#[proc_macro_derive(ComputeSquaredDistance, attributes(animation))]
+#[proc_macro_derive(ComputeSquaredDistance, attributes(animation, distance))]
pub fn derive_compute_squared_distance(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
compute_squared_distance::derive(input).to_string().parse().unwrap()
@@ -43,13 +43,13 @@ pub fn derive_to_animated_value(stream: TokenStream) -> TokenStream {
to_animated_value::derive(input).to_string().parse().unwrap()
}
-#[proc_macro_derive(ToAnimatedZero)]
+#[proc_macro_derive(ToAnimatedZero, attributes(animation))]
pub fn derive_to_animated_zero(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
to_animated_zero::derive(input).to_string().parse().unwrap()
}
-#[proc_macro_derive(ToComputedValue)]
+#[proc_macro_derive(ToComputedValue, attributes(compute))]
pub fn derive_to_computed_value(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
to_computed_value::derive(input).to_string().parse().unwrap()
diff --git a/components/style_derive/to_animated_value.rs b/components/style_derive/to_animated_value.rs
index 5a66ddf65a4..7865ba597e9 100644
--- a/components/style_derive/to_animated_value.rs
+++ b/components/style_derive/to_animated_value.rs
@@ -9,18 +9,16 @@ use synstructure::BindStyle;
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let name = &input.ident;
- let (impl_generics, ty_generics, where_clause, animated_value_type) =
- cg::fmap_trait_parts(
- &input,
- &["values", "animated", "ToAnimatedValue"],
- "AnimatedValue",
- );
+ let trait_path = &["values", "animated", "ToAnimatedValue"];
+ let (impl_generics, ty_generics, mut where_clause, animated_value_type) =
+ cg::fmap_trait_parts(&input, trait_path, "AnimatedValue");
- let to_body = cg::fmap_match(&input, BindStyle::Move, |field| {
- quote!(::values::animated::ToAnimatedValue::to_animated_value(#field))
+ let to_body = cg::fmap_match(&input, BindStyle::Move, |binding| {
+ where_clause.add_trait_bound(&binding.field.ty);
+ quote!(::values::animated::ToAnimatedValue::to_animated_value(#binding))
});
- let from_body = cg::fmap_match(&input, BindStyle::Move, |field| {
- quote!(::values::animated::ToAnimatedValue::from_animated_value(#field))
+ let from_body = cg::fmap_match(&input, BindStyle::Move, |binding| {
+ quote!(::values::animated::ToAnimatedValue::from_animated_value(#binding))
});
quote! {
diff --git a/components/style_derive/to_animated_zero.rs b/components/style_derive/to_animated_zero.rs
index d9e67a8a9fe..be1210faa7a 100644
--- a/components/style_derive/to_animated_zero.rs
+++ b/components/style_derive/to_animated_zero.rs
@@ -2,20 +2,51 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+use animate::{AnimationVariantAttrs, AnimationFieldAttrs};
use cg;
use quote;
use syn;
-use synstructure::BindStyle;
+use synstructure::{self, BindStyle};
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let name = &input.ident;
- let (impl_generics, ty_generics, where_clause) = cg::trait_parts(
- &input,
- &["values", "animated", "ToAnimatedZero"],
- );
+ let trait_path = &["values", "animated", "ToAnimatedZero"];
+ let (impl_generics, ty_generics, mut where_clause) =
+ cg::trait_parts(&input, trait_path);
- let to_body = cg::fmap_match(&input, BindStyle::Ref, |field| {
- quote! { ::values::animated::ToAnimatedZero::to_animated_zero(#field)? }
+ let bind_opts = BindStyle::Ref.into();
+ let to_body = synstructure::each_variant(&input, &bind_opts, |bindings, variant| {
+ let attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(variant);
+ if attrs.error {
+ return Some(quote! { Err(()) });
+ }
+ let name = cg::variant_ctor(&input, variant);
+ let (mapped, mapped_bindings) = cg::value(&name, variant, "mapped");
+ let bindings_pairs = bindings.into_iter().zip(mapped_bindings);
+ let mut computations = quote!();
+ computations.append_all(bindings_pairs.map(|(binding, mapped_binding)| {
+ let field_attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&binding.field);
+ if field_attrs.constant {
+ if cg::is_parameterized(&binding.field.ty, where_clause.params, None) {
+ where_clause.inner.predicates.push(cg::where_predicate(
+ binding.field.ty.clone(),
+ &["std", "clone", "Clone"],
+ None,
+ ));
+ }
+ quote! {
+ let #mapped_binding = ::std::clone::Clone::clone(#binding);
+ }
+ } else {
+ where_clause.add_trait_bound(&binding.field.ty);
+ quote! {
+ let #mapped_binding =
+ ::values::animated::ToAnimatedZero::to_animated_zero(#binding)?;
+ }
+ }
+ }));
+ computations.append(quote! { Ok(#mapped) });
+ Some(computations)
});
quote! {
@@ -23,9 +54,9 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
#[allow(unused_variables)]
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
- Ok(match *self {
+ match *self {
#to_body
- })
+ }
}
}
}
diff --git a/components/style_derive/to_computed_value.rs b/components/style_derive/to_computed_value.rs
index 967f3320a37..7e4db276edd 100644
--- a/components/style_derive/to_computed_value.rs
+++ b/components/style_derive/to_computed_value.rs
@@ -3,24 +3,43 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use cg;
-use quote;
-use syn;
+use quote::Tokens;
+use syn::DeriveInput;
use synstructure::BindStyle;
-pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
+pub fn derive(input: DeriveInput) -> Tokens {
let name = &input.ident;
- let (impl_generics, ty_generics, where_clause, computed_value_type) =
- cg::fmap_trait_parts(
- &input,
- &["values", "computed", "ToComputedValue"],
- "ComputedValue",
- );
+ let trait_path = &["values", "computed", "ToComputedValue"];
+ let (impl_generics, ty_generics, mut where_clause, computed_value_type) =
+ cg::fmap_trait_parts(&input, trait_path, "ComputedValue");
- let to_body = cg::fmap_match(&input, BindStyle::Ref, |field| {
- quote!(::values::computed::ToComputedValue::to_computed_value(#field, context))
+ let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| {
+ let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.field);
+ if attrs.clone {
+ if cg::is_parameterized(&binding.field.ty, where_clause.params, None) {
+ where_clause.inner.predicates.push(cg::where_predicate(
+ binding.field.ty.clone(),
+ &["std", "clone", "Clone"],
+ None,
+ ));
+ }
+ quote! { ::std::clone::Clone::clone(#binding) }
+ } else {
+ where_clause.add_trait_bound(&binding.field.ty);
+ quote! {
+ ::values::computed::ToComputedValue::to_computed_value(#binding, context)
+ }
+ }
});
- let from_body = cg::fmap_match(&input, BindStyle::Ref, |field| {
- quote!(::values::computed::ToComputedValue::from_computed_value(#field))
+ let from_body = cg::fmap_match(&input, BindStyle::Ref, |binding| {
+ let attrs = cg::parse_field_attrs::<ComputedValueAttrs>(&binding.field);
+ if attrs.clone {
+ quote! { ::std::clone::Clone::clone(#binding) }
+ } else {
+ quote! {
+ ::values::computed::ToComputedValue::from_computed_value(#binding)
+ }
+ }
});
quote! {
@@ -44,3 +63,9 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
}
}
}
+
+#[darling(attributes(compute), default)]
+#[derive(Default, FromField)]
+struct ComputedValueAttrs {
+ clone: bool,
+}
diff --git a/components/style_derive/to_css.rs b/components/style_derive/to_css.rs
index 444c42e37da..6ae438ccbd2 100644
--- a/components/style_derive/to_css.rs
+++ b/components/style_derive/to_css.rs
@@ -3,29 +3,26 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use cg;
-use quote;
-use syn;
+use quote::Tokens;
+use syn::DeriveInput;
use synstructure;
-pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
+pub fn derive(input: DeriveInput) -> Tokens {
let name = &input.ident;
let trait_path = &["style_traits", "ToCss"];
let (impl_generics, ty_generics, mut where_clause) =
cg::trait_parts(&input, trait_path);
+ let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
let style = synstructure::BindStyle::Ref.into();
let match_body = synstructure::each_variant(&input, &style, |bindings, variant| {
let mut identifier = to_css_identifier(variant.ident.as_ref());
- let css_attrs = cg::parse_variant_attrs::<CssAttrs>(variant);
- let separator = if css_attrs.comma { ", " } else { " " };
+ let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(variant);
+ let separator = if variant_attrs.comma { ", " } else { " " };
let mut expr = if !bindings.is_empty() {
let mut expr = quote! {};
for binding in bindings {
- if cg::is_parameterized(&binding.field.ty, &input.generics.ty_params) {
- where_clause.predicates.push(
- cg::where_predicate(binding.field.ty.clone(), trait_path),
- );
- }
+ where_clause.add_trait_bound(&binding.field.ty);
expr = quote! {
#expr
writer.item(#binding)?;
@@ -41,7 +38,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
::std::fmt::Write::write_str(dest, #identifier)
}
};
- if css_attrs.function {
+ if variant_attrs.function {
identifier.push_str("(");
expr = quote! {
::std::fmt::Write::write_str(dest, #identifier)?;
@@ -52,7 +49,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
Some(expr)
});
- quote! {
+ let mut impls = quote! {
impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause {
#[allow(unused_variables)]
#[inline]
@@ -65,12 +62,32 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
}
}
}
+ };
+
+ if input_attrs.derive_debug {
+ impls.append(quote! {
+ impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+ ::style_traits::ToCss::to_css(self, f)
+ }
+ }
+ });
}
+
+ impls
}
-#[derive(Default, FromVariant)]
#[darling(attributes(css), default)]
-struct CssAttrs {
+#[derive(Default, FromDeriveInput)]
+struct CssInputAttrs {
+ derive_debug: bool,
+ function: bool,
+ comma: bool,
+}
+
+#[darling(attributes(css), default)]
+#[derive(Default, FromVariant)]
+struct CssVariantAttrs {
function: bool,
comma: bool,
}
diff --git a/components/style_traits/values.rs b/components/style_traits/values.rs
index 5e4c093fd73..94e59e26bbe 100644
--- a/components/style_traits/values.rs
+++ b/components/style_traits/values.rs
@@ -18,8 +18,12 @@ use std::fmt::{self, Write};
/// of their name;
/// * unit variants whose name starts with "Moz" or "Webkit" are prepended
/// with a "-";
-/// * variants with fields get serialised as the space-separated serialisations
-/// of their fields.
+/// * if `#[css(comma)]` is found on a variant, its fields are separated by
+/// commas, otherwise, by spaces;
+/// * if `#[css(function)]` is found on a variant, the variant name gets
+/// serialised like unit variants and its fields are surrounded by parentheses;
+/// * finally, one can put `#[css(derive_debug)]` on the whole type, to
+/// implement `Debug` by a single call to `ToCss::to_css`.
pub trait ToCss {
/// Serialize `self` in CSS syntax, writing to `dest`.
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: Write;