mirror of
https://github.com/servo/servo.git
synced 2025-06-23 16:44:33 +01:00
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 -->
This commit is contained in:
commit
a266e96d28
27 changed files with 673 additions and 868 deletions
|
@ -48,9 +48,10 @@ use values::animated::effects::TextShadowList as AnimatedTextShadowList;
|
||||||
use values::computed::{Angle, BorderCornerRadius, CalcLengthOrPercentage};
|
use values::computed::{Angle, BorderCornerRadius, CalcLengthOrPercentage};
|
||||||
use values::computed::{ClipRect, Context, ComputedUrl, ComputedValueAsSpecified};
|
use values::computed::{ClipRect, Context, ComputedUrl, ComputedValueAsSpecified};
|
||||||
use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
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::{NonNegativeNumber, Number, NumberOrPercentage, Percentage};
|
||||||
use values::computed::{PositiveIntegerOrAuto, ToComputedValue};
|
use values::computed::{PositiveIntegerOrAuto, ToComputedValue};
|
||||||
|
#[cfg(feature = "gecko")] use values::computed::MozLength;
|
||||||
use values::computed::length::{NonNegativeLengthOrAuto, NonNegativeLengthOrNormal};
|
use values::computed::length::{NonNegativeLengthOrAuto, NonNegativeLengthOrNormal};
|
||||||
use values::computed::length::NonNegativeLengthOrPercentage;
|
use values::computed::length::NonNegativeLengthOrPercentage;
|
||||||
use values::distance::{ComputeSquaredDistance, SquaredDistance};
|
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 {
|
impl ToAnimatedZero for LengthOrPercentageOrAuto {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
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 {
|
impl ToAnimatedZero for LengthOrPercentageOrNone {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
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 {
|
impl ToAnimatedZero for MaxLength {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
|
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
|
||||||
|
@ -2431,27 +2284,6 @@ pub type IntermediateSVGPaint = SVGPaint<AnimatedRGBA, ComputedUrl>;
|
||||||
/// Animated SVGPaintKind
|
/// Animated SVGPaintKind
|
||||||
pub type IntermediateSVGPaintKind = SVGPaintKind<AnimatedRGBA, ComputedUrl>;
|
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 {
|
impl ToAnimatedZero for IntermediateSVGPaint {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
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 {
|
impl From<NonNegativeLengthOrPercentage> for NumberOrPercentage {
|
||||||
fn from(lop: NonNegativeLengthOrPercentage) -> NumberOrPercentage {
|
fn from(lop: NonNegativeLengthOrPercentage) -> NumberOrPercentage {
|
||||||
lop.0.into()
|
lop.0.into()
|
||||||
|
|
|
@ -1116,12 +1116,12 @@ ${helpers.single_keyword_system("font-variant-caps",
|
||||||
|
|
||||||
pub mod computed_value {
|
pub mod computed_value {
|
||||||
use values::CSSFloat;
|
use values::CSSFloat;
|
||||||
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
|
use values::animated::{ToAnimatedValue, ToAnimatedZero};
|
||||||
use values::distance::{ComputeSquaredDistance, SquaredDistance};
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, ToCss)]
|
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToCss)]
|
||||||
pub enum T {
|
pub enum T {
|
||||||
|
#[animation(error)]
|
||||||
None,
|
None,
|
||||||
Number(CSSFloat),
|
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 {
|
impl ToAnimatedZero for T {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
|
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"
|
predefined_type="Number" gecko_ffi_name="mScriptSizeMultiplier"
|
||||||
spec="Internal (not web-exposed)"
|
spec="Internal (not web-exposed)"
|
||||||
internal="True">
|
internal="True">
|
||||||
use values::computed::ComputedValueAsSpecified;
|
|
||||||
pub use self::computed_value::T as SpecifiedValue;
|
pub use self::computed_value::T as SpecifiedValue;
|
||||||
|
|
||||||
impl ComputedValueAsSpecified for SpecifiedValue {}
|
|
||||||
|
|
||||||
pub mod computed_value {
|
pub mod computed_value {
|
||||||
pub type T = f32;
|
pub type T = f32;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
impl ComputeSquaredDistance for BoxShadow {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
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 {
|
impl ToAnimatedValue for ComputedFilterList {
|
||||||
type AnimatedValue = FilterList;
|
type AnimatedValue = FilterList;
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,19 @@ use values::specified::url::SpecifiedUrl;
|
||||||
pub mod color;
|
pub mod color;
|
||||||
pub mod effects;
|
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 {
|
pub trait Animate: Sized {
|
||||||
/// Animate a value towards another one, given an animation procedure.
|
/// Animate a value towards another one, given an animation procedure.
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>;
|
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.
|
/// Conversion between computed values and intermediate values for animations.
|
||||||
///
|
///
|
||||||
/// Notably, colors are represented as four floats during animations.
|
/// Notably, colors are represented as four floats during animations.
|
||||||
|
///
|
||||||
|
/// This trait is derivable with `#[derive(ToAnimatedValue)]`.
|
||||||
pub trait ToAnimatedValue {
|
pub trait ToAnimatedValue {
|
||||||
/// The type of the animated value.
|
/// The type of the animated value.
|
||||||
type AnimatedValue;
|
type AnimatedValue;
|
||||||
|
@ -66,6 +80,13 @@ pub trait ToAnimatedValue {
|
||||||
pub trait AnimatedValueAsComputed {}
|
pub trait AnimatedValueAsComputed {}
|
||||||
|
|
||||||
/// Returns a value similar to `self` that represents zero.
|
/// 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 {
|
pub trait ToAnimatedZero: Sized {
|
||||||
/// Returns a value that, when added with an underlying value, will produce the underlying
|
/// 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
|
/// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from
|
||||||
|
|
|
@ -12,8 +12,10 @@ use values::animated::{Animate, Procedure};
|
||||||
use values::distance::{ComputeSquaredDistance, SquaredDistance};
|
use values::distance::{ComputeSquaredDistance, SquaredDistance};
|
||||||
|
|
||||||
/// A computed angle.
|
/// A computed angle.
|
||||||
|
#[animate(fallback = "Self::animate_fallback")]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
|
#[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 {
|
pub enum Angle {
|
||||||
/// An angle with degree unit.
|
/// An angle with degree unit.
|
||||||
Degree(CSSFloat),
|
Degree(CSSFloat),
|
||||||
|
@ -62,26 +64,11 @@ impl Angle {
|
||||||
pub fn zero() -> Self {
|
pub fn zero() -> Self {
|
||||||
Angle::Radian(0.0)
|
Angle::Radian(0.0)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-transitions/#animtype-number
|
/// https://drafts.csswg.org/css-transitions/#animtype-number
|
||||||
impl Animate for Angle {
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
fn animate_fallback(&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)?))
|
Ok(Angle::from_radians(self.radians().animate(&other.radians(), procedure)?))
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
use properties::animated_properties::RepeatableListAnimatable;
|
use properties::animated_properties::RepeatableListAnimatable;
|
||||||
use properties::longhands::background_size::computed_value::T as BackgroundSizeList;
|
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::computed::length::LengthOrPercentageOrAuto;
|
||||||
use values::generics::background::BackgroundSize as GenericBackgroundSize;
|
use values::generics::background::BackgroundSize as GenericBackgroundSize;
|
||||||
|
|
||||||
|
@ -15,23 +15,6 @@ pub type BackgroundSize = GenericBackgroundSize<LengthOrPercentageOrAuto>;
|
||||||
|
|
||||||
impl RepeatableListAnimatable for BackgroundSize {}
|
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 {
|
impl ToAnimatedZero for BackgroundSize {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
|
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
|
||||||
|
|
|
@ -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::{Gradient as GenericGradient, GradientItem as GenericGradientItem};
|
||||||
use values::generics::image::{Image as GenericImage, GradientKind as GenericGradientKind};
|
use values::generics::image::{Image as GenericImage, GradientKind as GenericGradientKind};
|
||||||
use values::generics::image::{LineDirection as GenericLineDirection, MozImageRect as GenericMozImageRect};
|
use values::generics::image::{LineDirection as GenericLineDirection, MozImageRect as GenericMozImageRect};
|
||||||
use values::specified::image::{Gradient as SpecifiedGradient, LineDirection as SpecifiedLineDirection};
|
use values::specified::image::LineDirection as SpecifiedLineDirection;
|
||||||
use values::specified::image::{GradientKind as SpecifiedGradientKind};
|
|
||||||
use values::specified::position::{X, Y};
|
use values::specified::position::{X, Y};
|
||||||
|
|
||||||
/// A computed image layer.
|
/// 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)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use style_traits::ToCss;
|
||||||
use style_traits::values::specified::AllowedLengthType;
|
use style_traits::values::specified::AllowedLengthType;
|
||||||
use super::{Number, ToComputedValue, Context, Percentage};
|
use super::{Number, ToComputedValue, Context, Percentage};
|
||||||
use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
|
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::computed::{NonNegativeAu, NonNegativeNumber};
|
||||||
use values::distance::{ComputeSquaredDistance, SquaredDistance};
|
use values::distance::{ComputeSquaredDistance, SquaredDistance};
|
||||||
use values::generics::NonNegative;
|
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)]
|
#[allow(missing_docs)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, ToAnimatedZero)]
|
||||||
pub struct CalcLengthOrPercentage {
|
pub struct CalcLengthOrPercentage {
|
||||||
|
#[animation(constant)]
|
||||||
pub clamping_mode: AllowedLengthType,
|
pub clamping_mode: AllowedLengthType,
|
||||||
length: Au,
|
length: Au,
|
||||||
pub percentage: Option<Percentage>,
|
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 {
|
impl ComputeSquaredDistance for CalcLengthOrPercentage {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
||||||
|
@ -285,28 +275,47 @@ impl ToComputedValue for specified::CalcLengthOrPercentage {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
|
#[animate(fallback = "Self::animate_fallback")]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[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 {
|
pub enum LengthOrPercentage {
|
||||||
Length(Au),
|
Length(Au),
|
||||||
Percentage(Percentage),
|
Percentage(Percentage),
|
||||||
Calc(CalcLengthOrPercentage),
|
Calc(CalcLengthOrPercentage),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputeSquaredDistance for LengthOrPercentage {
|
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]
|
#[inline]
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
fn compute_squared_distance_fallback(
|
||||||
match (self, other) {
|
&self,
|
||||||
(&LengthOrPercentage::Length(ref this), &LengthOrPercentage::Length(ref other)) => {
|
other: &Self,
|
||||||
this.compute_squared_distance(other)
|
) -> Result<SquaredDistance, ()> {
|
||||||
},
|
CalcLengthOrPercentage::compute_squared_distance(
|
||||||
(&LengthOrPercentage::Percentage(ref this), &LengthOrPercentage::Percentage(ref other)) => {
|
&(*self).into(),
|
||||||
this.compute_squared_distance(other)
|
&(*other).into(),
|
||||||
},
|
)
|
||||||
(this, other) => {
|
|
||||||
CalcLengthOrPercentage::compute_squared_distance(&(*this).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 {
|
impl ToComputedValue for specified::LengthOrPercentage {
|
||||||
type ComputedValue = LengthOrPercentage;
|
type ComputedValue = LengthOrPercentage;
|
||||||
|
|
||||||
|
@ -426,8 +425,11 @@ impl ToComputedValue for specified::LengthOrPercentage {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
|
#[animate(fallback = "Self::animate_fallback")]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[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 {
|
pub enum LengthOrPercentageOrAuto {
|
||||||
Length(Au),
|
Length(Au),
|
||||||
Percentage(Percentage),
|
Percentage(Percentage),
|
||||||
|
@ -435,20 +437,29 @@ pub enum LengthOrPercentageOrAuto {
|
||||||
Calc(CalcLengthOrPercentage),
|
Calc(CalcLengthOrPercentage),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputeSquaredDistance for LengthOrPercentageOrAuto {
|
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]
|
#[inline]
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
fn compute_squared_distance_fallback(
|
||||||
match (self, other) {
|
&self,
|
||||||
(&LengthOrPercentageOrAuto::Length(ref this), &LengthOrPercentageOrAuto::Length(ref other)) => {
|
other: &Self,
|
||||||
this.compute_squared_distance(other)
|
) -> Result<SquaredDistance, ()> {
|
||||||
},
|
<Option<CalcLengthOrPercentage>>::compute_squared_distance(
|
||||||
(&LengthOrPercentageOrAuto::Percentage(ref this), &LengthOrPercentageOrAuto::Percentage(ref other)) => {
|
&(*self).into(),
|
||||||
this.compute_squared_distance(other)
|
&(*other).into(),
|
||||||
},
|
)
|
||||||
(this, other) => {
|
|
||||||
<Option<CalcLengthOrPercentage>>::compute_squared_distance(&(*this).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 {
|
impl ToComputedValue for specified::LengthOrPercentageOrAuto {
|
||||||
type ComputedValue = LengthOrPercentageOrAuto;
|
type ComputedValue = LengthOrPercentageOrAuto;
|
||||||
|
|
||||||
|
@ -521,8 +521,11 @@ impl ToComputedValue for specified::LengthOrPercentageOrAuto {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
|
#[animate(fallback = "Self::animate_fallback")]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[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 {
|
pub enum LengthOrPercentageOrNone {
|
||||||
Length(Au),
|
Length(Au),
|
||||||
Percentage(Percentage),
|
Percentage(Percentage),
|
||||||
|
@ -530,20 +533,28 @@ pub enum LengthOrPercentageOrNone {
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputeSquaredDistance for LengthOrPercentageOrNone {
|
impl LengthOrPercentageOrNone {
|
||||||
#[inline]
|
/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
fn animate_fallback(
|
||||||
match (self, other) {
|
&self,
|
||||||
(&LengthOrPercentageOrNone::Length(ref this), &LengthOrPercentageOrNone::Length(ref other)) => {
|
other: &Self,
|
||||||
this.compute_squared_distance(other)
|
procedure: Procedure,
|
||||||
},
|
) -> Result<Self, ()> {
|
||||||
(&LengthOrPercentageOrNone::Percentage(ref this), &LengthOrPercentageOrNone::Percentage(ref other)) => {
|
let this = <Option<CalcLengthOrPercentage>>::from(*self);
|
||||||
this.compute_squared_distance(other)
|
let other = <Option<CalcLengthOrPercentage>>::from(*other);
|
||||||
},
|
Ok(LengthOrPercentageOrNone::Calc(
|
||||||
(this, other) => {
|
this.animate(&other, procedure)?.ok_or(())?,
|
||||||
<Option<CalcLengthOrPercentage>>::compute_squared_distance(&(*this).into(), &(*other).into())
|
))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
impl ToComputedValue for specified::LengthOrPercentageOrNone {
|
||||||
type ComputedValue = LengthOrPercentageOrNone;
|
type ComputedValue = LengthOrPercentageOrNone;
|
||||||
|
|
||||||
|
@ -695,28 +695,14 @@ pub type NonNegativeLengthOrNumber = Either<NonNegativeLength, NonNegativeNumber
|
||||||
/// See values/specified/length.rs for more details.
|
/// See values/specified/length.rs for more details.
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[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 {
|
pub enum MozLength {
|
||||||
LengthOrPercentageOrAuto(LengthOrPercentageOrAuto),
|
LengthOrPercentageOrAuto(LengthOrPercentageOrAuto),
|
||||||
|
#[animation(error)]
|
||||||
ExtremumLength(ExtremumLength),
|
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 {
|
impl MozLength {
|
||||||
/// Returns the `auto` value.
|
/// Returns the `auto` value.
|
||||||
pub fn auto() -> Self {
|
pub fn auto() -> Self {
|
||||||
|
@ -755,28 +741,13 @@ impl ToComputedValue for specified::MozLength {
|
||||||
/// See values/specified/length.rs for more details.
|
/// See values/specified/length.rs for more details.
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, ToCss)]
|
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToCss)]
|
||||||
pub enum MaxLength {
|
pub enum MaxLength {
|
||||||
LengthOrPercentageOrNone(LengthOrPercentageOrNone),
|
LengthOrPercentageOrNone(LengthOrPercentageOrNone),
|
||||||
|
#[animation(error)]
|
||||||
ExtremumLength(ExtremumLength),
|
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 {
|
impl MaxLength {
|
||||||
/// Returns the `none` value.
|
/// Returns the `none` value.
|
||||||
pub fn none() -> Self {
|
pub fn none() -> Self {
|
||||||
|
|
|
@ -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.
|
/// 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 {
|
pub trait ToComputedValue {
|
||||||
/// The computed value type we're going to be converted to.
|
/// The computed value type we're going to be converted to.
|
||||||
type ComputedValue;
|
type ComputedValue;
|
||||||
|
@ -327,6 +332,7 @@ impl<T> ToComputedValue for T
|
||||||
|
|
||||||
impl ComputedValueAsSpecified for Atom {}
|
impl ComputedValueAsSpecified for Atom {}
|
||||||
impl ComputedValueAsSpecified for bool {}
|
impl ComputedValueAsSpecified for bool {}
|
||||||
|
impl ComputedValueAsSpecified for f32 {}
|
||||||
|
|
||||||
impl ComputedValueAsSpecified for specified::BorderStyle {}
|
impl ComputedValueAsSpecified for specified::BorderStyle {}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,17 @@ use std::iter::Sum;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
|
|
||||||
/// A trait to compute squared distances between two animatable values.
|
/// 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 {
|
pub trait ComputeSquaredDistance {
|
||||||
/// Computes the squared distance between two animatable values.
|
/// Computes the squared distance between two animatable values.
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>;
|
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()>;
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
//! Generic types for CSS values related to backgrounds.
|
//! Generic types for CSS values related to backgrounds.
|
||||||
|
|
||||||
/// A generic value for the `background-size` property.
|
/// A generic value for the `background-size` property.
|
||||||
#[derive(Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug)]
|
||||||
|
#[derive(HasViewportPercentage, PartialEq, ToComputedValue, ToCss)]
|
||||||
pub enum BackgroundSize<LengthOrPercentageOrAuto> {
|
pub enum BackgroundSize<LengthOrPercentageOrAuto> {
|
||||||
/// `<width> <height>`
|
/// `<width> <height>`
|
||||||
Explicit {
|
Explicit {
|
||||||
|
@ -16,8 +17,10 @@ pub enum BackgroundSize<LengthOrPercentageOrAuto> {
|
||||||
height: LengthOrPercentageOrAuto
|
height: LengthOrPercentageOrAuto
|
||||||
},
|
},
|
||||||
/// `cover`
|
/// `cover`
|
||||||
|
#[animation(error)]
|
||||||
Cover,
|
Cover,
|
||||||
/// `contain`
|
/// `contain`
|
||||||
|
#[animation(error)]
|
||||||
Contain,
|
Contain,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,11 +44,18 @@ add_impls_for_keyword_enum!(ShapeBox);
|
||||||
/// A shape source, for some reference box.
|
/// A shape source, for some reference box.
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[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> {
|
pub enum ShapeSource<BasicShape, ReferenceBox, Url> {
|
||||||
|
#[animation(error)]
|
||||||
Url(Url),
|
Url(Url),
|
||||||
Shape(BasicShape, Option<ReferenceBox>),
|
Shape(
|
||||||
|
BasicShape,
|
||||||
|
#[animation(constant)]
|
||||||
|
Option<ReferenceBox>,
|
||||||
|
),
|
||||||
|
#[animation(error)]
|
||||||
Box(ReferenceBox),
|
Box(ReferenceBox),
|
||||||
|
#[animation(error)]
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,10 +101,13 @@ pub struct Ellipse<H, V, LengthOrPercentage> {
|
||||||
/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
|
/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[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> {
|
pub enum ShapeRadius<LengthOrPercentage> {
|
||||||
Length(LengthOrPercentage),
|
Length(LengthOrPercentage),
|
||||||
|
#[animation(error)]
|
||||||
ClosestSide,
|
ClosestSide,
|
||||||
|
#[animation(error)]
|
||||||
FarthestSide,
|
FarthestSide,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,29 +133,6 @@ define_css_keyword_enum!(FillRule:
|
||||||
);
|
);
|
||||||
add_impls_for_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
|
// FIXME(nox): Implement ComputeSquaredDistance for T types and stop
|
||||||
// using PartialEq here, this will let us derive this impl.
|
// using PartialEq here, this will let us derive this impl.
|
||||||
impl<B, T, U> ComputeSquaredDistance for ShapeSource<B, T, U>
|
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> {
|
impl<L> Default for ShapeRadius<L> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Self { ShapeRadius::ClosestSide }
|
fn default() -> Self { ShapeRadius::ClosestSide }
|
||||||
|
|
|
@ -11,13 +11,15 @@ use values::specified::url::SpecifiedUrl;
|
||||||
|
|
||||||
/// A generic value for a single `box-shadow`.
|
/// A generic value for a single `box-shadow`.
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[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> {
|
pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
|
||||||
/// The base shadow.
|
/// The base shadow.
|
||||||
pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>,
|
pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>,
|
||||||
/// The spread radius.
|
/// The spread radius.
|
||||||
pub spread: ShapeLength,
|
pub spread: ShapeLength,
|
||||||
/// Whether this is an inset box shadow.
|
/// Whether this is an inset box shadow.
|
||||||
|
#[animation(constant)]
|
||||||
pub inset: bool,
|
pub inset: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use parser::{Parse, ParserContext};
|
||||||
use std::{fmt, mem, usize};
|
use std::{fmt, mem, usize};
|
||||||
use style_traits::{ToCss, ParseError, StyleParseError};
|
use style_traits::{ToCss, ParseError, StyleParseError};
|
||||||
use values::{CSSFloat, CustomIdent, serialize_dimension};
|
use values::{CSSFloat, CustomIdent, serialize_dimension};
|
||||||
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
|
use values::computed::ComputedValueAsSpecified;
|
||||||
use values::specified::Integer;
|
use values::specified::Integer;
|
||||||
use values::specified::grid::parse_line_names;
|
use values::specified::grid::parse_line_names;
|
||||||
|
|
||||||
|
@ -137,13 +137,14 @@ define_css_keyword_enum!{ TrackKeyword:
|
||||||
"max-content" => MaxContent,
|
"max-content" => MaxContent,
|
||||||
"min-content" => MinContent
|
"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
|
/// A track breadth for explicit grid track sizing. It's generic solely to
|
||||||
/// avoid re-implementing it for the computed type.
|
/// avoid re-implementing it for the computed type.
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-grid/#typedef-track-breadth
|
/// https://drafts.csswg.org/css-grid/#typedef-track-breadth
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
|
||||||
pub enum TrackBreadth<L> {
|
pub enum TrackBreadth<L> {
|
||||||
/// The generic type is almost always a non-negative `<length-percentage>`
|
/// The generic type is almost always a non-negative `<length-percentage>`
|
||||||
Breadth(L),
|
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
|
/// 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>`
|
/// generic only to avoid code bloat. It only takes `<length-percentage>`
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-grid/#typedef-track-size
|
/// https://drafts.csswg.org/css-grid/#typedef-track-size
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
|
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
|
||||||
pub enum TrackSize<L> {
|
pub enum TrackSize<L> {
|
||||||
/// A flexible `<track-breadth>`
|
/// A flexible `<track-breadth>`
|
||||||
Breadth(TrackBreadth<L>),
|
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
|
/// Helper function for serializing identifiers with a prefix and suffix, used
|
||||||
/// for serializing <line-names> (in grid).
|
/// for serializing <line-names> (in grid).
|
||||||
pub fn concat_serialize_idents<W>(prefix: &str, suffix: &str,
|
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
|
/// It can also hold `repeat()` function parameters, which expands into the respective
|
||||||
/// values in its computed form.
|
/// values in its computed form.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
|
||||||
pub struct TrackRepeat<L> {
|
pub struct TrackRepeat<L> {
|
||||||
/// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`)
|
/// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`)
|
||||||
pub count: RepeatCount,
|
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.
|
/// 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
|
/// 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>`.
|
/// length is always one value more than that of the `<track-size>`.
|
||||||
|
#[compute(clone)]
|
||||||
pub line_names: Box<[Box<[CustomIdent]>]>,
|
pub line_names: Box<[Box<[CustomIdent]>]>,
|
||||||
/// `<track-size>` values.
|
/// `<track-size>` values.
|
||||||
pub track_sizes: Vec<TrackSize<L>>,
|
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.
|
/// The type of a `<track-list>` as determined during parsing.
|
||||||
///
|
///
|
||||||
|
@ -533,8 +454,8 @@ impl ComputedValueAsSpecified for TrackListType {}
|
||||||
/// A grid `<track-list>` type.
|
/// A grid `<track-list>` type.
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-grid/#typedef-track-list
|
/// https://drafts.csswg.org/css-grid/#typedef-track-list
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
|
||||||
pub struct TrackList<T> {
|
pub struct TrackList<T> {
|
||||||
/// The type of this `<track-list>` (auto, explicit or general).
|
/// 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.
|
/// 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
|
/// 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>`.
|
/// length is always one value more than that of the `<track-size>`.
|
||||||
|
#[compute(clone)]
|
||||||
pub line_names: Box<[Box<[CustomIdent]>]>,
|
pub line_names: Box<[Box<[CustomIdent]>]>,
|
||||||
/// `<auto-repeat>` value. There can only be one `<auto-repeat>` in a TrackList.
|
/// `<auto-repeat>` value. There can only be one `<auto-repeat>` in a TrackList.
|
||||||
pub auto_repeat: Option<TrackRepeat<T>>,
|
pub auto_repeat: Option<TrackRepeat<T>>,
|
||||||
|
@ -698,8 +620,8 @@ no_viewport_percentage!(LineNameList);
|
||||||
/// Variants for `<grid-template-rows> | <grid-template-columns>`
|
/// Variants for `<grid-template-rows> | <grid-template-columns>`
|
||||||
/// Subgrid deferred to Level 2 spec due to lack of implementation.
|
/// Subgrid deferred to Level 2 spec due to lack of implementation.
|
||||||
/// But it's implemented in gecko, so we have to as well.
|
/// But it's implemented in gecko, so we have to as well.
|
||||||
#[derive(Clone, Debug, PartialEq, ToCss)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[derive(Clone, Debug, PartialEq, ToComputedValue, ToCss)]
|
||||||
pub enum GridTemplateComponent<L> {
|
pub enum GridTemplateComponent<L> {
|
||||||
/// `none` value.
|
/// `none` value.
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -35,16 +35,18 @@ pub enum Image<Gradient, MozImageRect, ImageUrl> {
|
||||||
|
|
||||||
/// A CSS gradient.
|
/// A CSS gradient.
|
||||||
/// https://drafts.csswg.org/css-images/#gradients
|
/// https://drafts.csswg.org/css-images/#gradients
|
||||||
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
|
||||||
pub struct Gradient<LineDirection, Length, LengthOrPercentage, Position, Color, Angle> {
|
pub struct Gradient<LineDirection, Length, LengthOrPercentage, Position, Color, Angle> {
|
||||||
/// Gradients can be linear or radial.
|
/// Gradients can be linear or radial.
|
||||||
pub kind: GradientKind<LineDirection, Length, LengthOrPercentage, Position, Angle>,
|
pub kind: GradientKind<LineDirection, Length, LengthOrPercentage, Position, Angle>,
|
||||||
/// The color stops and interpolation hints.
|
/// The color stops and interpolation hints.
|
||||||
pub items: Vec<GradientItem<Color, LengthOrPercentage>>,
|
pub items: Vec<GradientItem<Color, LengthOrPercentage>>,
|
||||||
/// True if this is a repeating gradient.
|
/// True if this is a repeating gradient.
|
||||||
|
#[compute(clone)]
|
||||||
pub repeating: bool,
|
pub repeating: bool,
|
||||||
/// Compatibility mode.
|
/// Compatibility mode.
|
||||||
|
#[compute(clone)]
|
||||||
pub compat_mode: CompatMode,
|
pub compat_mode: CompatMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,8 +63,8 @@ pub enum CompatMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A gradient kind.
|
/// A gradient kind.
|
||||||
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
|
||||||
pub enum GradientKind<LineDirection, Length, LengthOrPercentage, Position, Angle> {
|
pub enum GradientKind<LineDirection, Length, LengthOrPercentage, Position, Angle> {
|
||||||
/// A linear gradient.
|
/// A linear gradient.
|
||||||
Linear(LineDirection),
|
Linear(LineDirection),
|
||||||
|
|
|
@ -16,7 +16,8 @@ use values::distance::{ComputeSquaredDistance, SquaredDistance};
|
||||||
///
|
///
|
||||||
/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
|
/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[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> {
|
pub struct SVGPaint<ColorType, UrlPaintServer> {
|
||||||
/// The paint source
|
/// The paint source
|
||||||
pub kind: SVGPaintKind<ColorType, UrlPaintServer>,
|
pub kind: SVGPaintKind<ColorType, UrlPaintServer>,
|
||||||
|
@ -30,13 +31,15 @@ pub struct SVGPaint<ColorType, UrlPaintServer> {
|
||||||
/// to have a fallback, Gecko lets the context
|
/// to have a fallback, Gecko lets the context
|
||||||
/// properties have a fallback as well.
|
/// properties have a fallback as well.
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[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> {
|
pub enum SVGPaintKind<ColorType, UrlPaintServer> {
|
||||||
/// `none`
|
/// `none`
|
||||||
None,
|
None,
|
||||||
/// `<color>`
|
/// `<color>`
|
||||||
Color(ColorType),
|
Color(ColorType),
|
||||||
/// `url(...)`
|
/// `url(...)`
|
||||||
|
#[animation(error)]
|
||||||
PaintServer(UrlPaintServer),
|
PaintServer(UrlPaintServer),
|
||||||
/// `context-fill`
|
/// `context-fill`
|
||||||
ContextFill,
|
ContextFill,
|
||||||
|
|
|
@ -11,7 +11,6 @@ use std::ascii::AsciiExt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use style_traits::{HasViewportPercentage, ParseError, StyleParseError};
|
use style_traits::{HasViewportPercentage, ParseError, StyleParseError};
|
||||||
use values::{CSSFloat, CustomIdent};
|
use values::{CSSFloat, CustomIdent};
|
||||||
use values::computed::{self, Context, ToComputedValue};
|
|
||||||
use values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth, TrackKeyword, TrackRepeat};
|
use values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth, TrackKeyword, TrackRepeat};
|
||||||
use values::generics::grid::{LineNameList, TrackSize, TrackList, TrackListType};
|
use values::generics::grid::{LineNameList, TrackSize, TrackList, TrackListType};
|
||||||
use values::specified::LengthOrPercentage;
|
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> {
|
impl Parse for GridTemplateComponent<LengthOrPercentage> {
|
||||||
// FIXME: Derive Parse (probably with None_)
|
// FIXME: Derive Parse (probably with None_)
|
||||||
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
|
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)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,21 +3,22 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use cg;
|
use cg;
|
||||||
use quote;
|
use quote::Tokens;
|
||||||
use syn;
|
use syn::{DeriveInput, Path};
|
||||||
|
|
||||||
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
pub fn derive(input: DeriveInput) -> Tokens {
|
||||||
let name = &input.ident;
|
let name = &input.ident;
|
||||||
let trait_path = &["values", "animated", "Animate"];
|
let trait_path = &["values", "animated", "Animate"];
|
||||||
let (impl_generics, ty_generics, mut where_clause) =
|
let (impl_generics, ty_generics, mut where_clause) =
|
||||||
cg::trait_parts(&input, trait_path);
|
cg::trait_parts(&input, trait_path);
|
||||||
|
|
||||||
|
let input_attrs = cg::parse_input_attrs::<AnimateInputAttrs>(&input);
|
||||||
let variants = cg::variants(&input);
|
let variants = cg::variants(&input);
|
||||||
let mut match_body = quote!();
|
let mut match_body = quote!();
|
||||||
let mut append_error_clause = variants.len() > 1;
|
let mut append_error_clause = variants.len() > 1;
|
||||||
match_body.append_all(variants.iter().flat_map(|variant| {
|
match_body.append_all(variants.iter().flat_map(|variant| {
|
||||||
let attrs = cg::parse_variant_attrs::<AnimateAttrs>(variant);
|
let variant_attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(variant);
|
||||||
if attrs.error {
|
if variant_attrs.error {
|
||||||
append_error_clause = true;
|
append_error_clause = true;
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -28,11 +29,32 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
let mut computations = quote!();
|
let mut computations = quote!();
|
||||||
let iter = result_info.iter().zip(this_info.iter().zip(&other_info));
|
let iter = result_info.iter().zip(this_info.iter().zip(&other_info));
|
||||||
computations.append_all(iter.map(|(result, (this, other))| {
|
computations.append_all(iter.map(|(result, (this, other))| {
|
||||||
where_clause.predicates.push(
|
let field_attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&result.field);
|
||||||
cg::where_predicate(this.field.ty.clone(), trait_path),
|
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! {
|
quote! {
|
||||||
let #result = ::values::animated::Animate::animate(#this, #other, procedure)?;
|
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! {
|
Some(quote! {
|
||||||
|
@ -44,7 +66,13 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if append_error_clause {
|
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! {
|
quote! {
|
||||||
|
@ -64,8 +92,20 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, FromVariant)]
|
|
||||||
#[darling(attributes(animate), default)]
|
#[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,
|
pub error: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[darling(attributes(animation), default)]
|
||||||
|
#[derive(Default, FromField)]
|
||||||
|
pub struct AnimationFieldAttrs {
|
||||||
|
pub constant: bool,
|
||||||
|
}
|
||||||
|
|
|
@ -2,17 +2,86 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use darling::FromVariant;
|
use darling::{FromDeriveInput, FromField, FromVariant};
|
||||||
use quote::Tokens;
|
use quote::{ToTokens, Tokens};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use syn::{AngleBracketedParameterData, Body, DeriveInput, Ident, ImplGenerics};
|
use syn::{self, AngleBracketedParameterData, Body, DeriveInput, Field, Ident};
|
||||||
use syn::{Path, PathParameters, PathSegment, PolyTraitRef, QSelf};
|
use syn::{ImplGenerics, Path, PathParameters, PathSegment, PolyTraitRef};
|
||||||
use syn::{TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound, TypeBinding};
|
use syn::{QSelf, TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound};
|
||||||
use syn::{Variant, WhereBoundPredicate, WhereClause, WherePredicate};
|
use syn::{TypeBinding, Variant, WhereBoundPredicate, WherePredicate};
|
||||||
use syn::visit::{self, Visitor};
|
use syn::visit::{self, Visitor};
|
||||||
use synstructure::{self, BindOpts, BindStyle, BindingInfo};
|
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>(
|
pub fn fmap_match<F>(
|
||||||
input: &DeriveInput,
|
input: &DeriveInput,
|
||||||
bind_style: BindStyle,
|
bind_style: BindStyle,
|
||||||
|
@ -35,23 +104,36 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fmap_trait_parts<'a>(
|
fn fmap_output_type(
|
||||||
input: &'a DeriveInput,
|
ty: Ty,
|
||||||
trait_path: &[&str],
|
trait_path: &[&str],
|
||||||
trait_output: &str,
|
trait_output: &str,
|
||||||
) -> (ImplGenerics<'a>, TyGenerics<'a>, WhereClause, Path) {
|
) -> Ty {
|
||||||
let (impl_generics, ty_generics, where_clause) = trait_parts(input, trait_path);
|
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 {
|
let output_ty = PathSegment {
|
||||||
ident: input.ident.clone(),
|
ident: input.ident.clone(),
|
||||||
parameters: PathParameters::AngleBracketed(AngleBracketedParameterData {
|
parameters: PathParameters::AngleBracketed(AngleBracketedParameterData {
|
||||||
lifetimes: input.generics.lifetimes.iter().map(|l| l.lifetime.clone()).collect(),
|
lifetimes: input.generics.lifetimes.iter().map(|l| l.lifetime.clone()).collect(),
|
||||||
types: input.generics.ty_params.iter().map(|ty| {
|
types: input.generics.ty_params.iter().map(|ty| {
|
||||||
Ty::Path(
|
fmap_output_type(
|
||||||
Some(QSelf {
|
Ty::Path(None, ty.ident.clone().into()),
|
||||||
ty: Box::new(Ty::Path(None, ty.ident.clone().into())),
|
trait_path,
|
||||||
position: trait_path.len(),
|
trait_output,
|
||||||
}),
|
|
||||||
path(trait_path.iter().chain(iter::once(&trait_output))),
|
|
||||||
)
|
)
|
||||||
}).collect(),
|
}).collect(),
|
||||||
.. Default::default()
|
.. Default::default()
|
||||||
|
@ -60,25 +142,188 @@ pub fn fmap_trait_parts<'a>(
|
||||||
(impl_generics, ty_generics, where_clause, output_ty)
|
(impl_generics, ty_generics, where_clause, output_ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmap_trait_where_predicate(
|
pub fn is_parameterized(
|
||||||
bounded_ty: Ty,
|
ty: &Ty,
|
||||||
trait_path: &[&str],
|
params: &[TyParam],
|
||||||
trait_output: Option<(&str, Ty)>,
|
found: Option<&mut HashSet<Ident>>,
|
||||||
) -> WherePredicate {
|
) -> bool {
|
||||||
WherePredicate::BoundPredicate(WhereBoundPredicate {
|
struct IsParameterized<'a, 'b> {
|
||||||
bound_lifetimes: vec![],
|
params: &'a [TyParam],
|
||||||
bounded_ty,
|
has_free: bool,
|
||||||
bounds: vec![TyParamBound::Trait(
|
found: Option<&'b mut HashSet<Ident>>,
|
||||||
PolyTraitRef {
|
}
|
||||||
bound_lifetimes: vec![],
|
|
||||||
trait_ref: fmap_trait_ref(trait_path, trait_output),
|
impl<'a, 'b> Visitor for IsParameterized<'a, 'b> {
|
||||||
},
|
fn visit_path(&mut self, path: &Path) {
|
||||||
TraitBoundModifier::None
|
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, has_free: false, found };
|
||||||
|
visitor.visit_ty(ty);
|
||||||
|
visitor.has_free
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmap_trait_ref(path: &[&str], output: Option<(&str, Ty)>) -> Path {
|
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,
|
||||||
|
<S as IntoIterator>::Item: AsRef<str>,
|
||||||
|
{
|
||||||
|
Path {
|
||||||
|
global: true,
|
||||||
|
segments: segments.into_iter().map(|s| s.as_ref().into()).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 variant attributes: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ref_pattern<'a>(
|
||||||
|
name: &Ident,
|
||||||
|
variant: &'a Variant,
|
||||||
|
prefix: &str,
|
||||||
|
) -> (Tokens, Vec<BindingInfo<'a>>) {
|
||||||
|
synstructure::match_pattern(
|
||||||
|
&name,
|
||||||
|
&variant.data,
|
||||||
|
&BindOpts::with_prefix(BindStyle::Ref, prefix.to_owned()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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 (name, parent) = path.split_last().unwrap();
|
||||||
let last_segment = PathSegment {
|
let last_segment = PathSegment {
|
||||||
ident: (*name).into(),
|
ident: (*name).into(),
|
||||||
|
@ -104,77 +349,6 @@ fn fmap_trait_ref(path: &[&str], output: Option<(&str, Ty)>) -> Path {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_parameterized(ty: &Ty, params: &[TyParam]) -> bool {
|
|
||||||
struct IsParameterized<'a> {
|
|
||||||
params: &'a [TyParam],
|
|
||||||
has_free: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Visitor for IsParameterized<'a> {
|
|
||||||
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) {
|
|
||||||
self.has_free = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
visit::walk_path(self, path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut visitor = IsParameterized { params: params, has_free: false };
|
|
||||||
visitor.visit_ty(ty);
|
|
||||||
visitor.has_free
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path<S>(segments: S) -> Path
|
|
||||||
where
|
|
||||||
S: IntoIterator,
|
|
||||||
<S as IntoIterator>::Item: AsRef<str>,
|
|
||||||
{
|
|
||||||
Path {
|
|
||||||
global: true,
|
|
||||||
segments: segments.into_iter().map(|s| s.as_ref().into()).collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ref_pattern<'a>(
|
|
||||||
name: &Ident,
|
|
||||||
variant: &'a Variant,
|
|
||||||
prefix: &str,
|
|
||||||
) -> (Tokens, Vec<BindingInfo<'a>>) {
|
|
||||||
synstructure::match_pattern(
|
|
||||||
&name,
|
|
||||||
&variant.data,
|
|
||||||
&BindOpts::with_prefix(BindStyle::Ref, prefix.to_owned()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn trait_parts<'a>(
|
|
||||||
input: &'a DeriveInput,
|
|
||||||
trait_path: &[&str],
|
|
||||||
) -> (ImplGenerics<'a>, TyGenerics<'a>, WhereClause) {
|
|
||||||
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,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
(impl_generics, ty_generics, where_clause)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn value<'a>(
|
pub fn value<'a>(
|
||||||
name: &Ident,
|
name: &Ident,
|
||||||
variant: &'a Variant,
|
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 {
|
WherePredicate::BoundPredicate(WhereBoundPredicate {
|
||||||
bound_lifetimes: vec![],
|
bound_lifetimes: vec![],
|
||||||
bounded_ty: ty,
|
bounded_ty,
|
||||||
bounds: vec![TyParamBound::Trait(
|
bounds: vec![TyParamBound::Trait(
|
||||||
PolyTraitRef {
|
PolyTraitRef {
|
||||||
bound_lifetimes: vec![],
|
bound_lifetimes: vec![],
|
||||||
trait_ref: path(segments),
|
trait_ref: trait_ref(trait_path, trait_output),
|
||||||
},
|
},
|
||||||
TraitBoundModifier::None,
|
TraitBoundModifier::None
|
||||||
)],
|
)],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,22 +2,23 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use animate::AnimateAttrs;
|
use animate::AnimationVariantAttrs;
|
||||||
use cg;
|
use cg;
|
||||||
use quote;
|
use quote::Tokens;
|
||||||
use syn;
|
use syn::{DeriveInput, Path};
|
||||||
|
|
||||||
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
pub fn derive(input: DeriveInput) -> Tokens {
|
||||||
let name = &input.ident;
|
let name = &input.ident;
|
||||||
let trait_path = &["values", "distance", "ComputeSquaredDistance"];
|
let trait_path = &["values", "distance", "ComputeSquaredDistance"];
|
||||||
let (impl_generics, ty_generics, mut where_clause) =
|
let (impl_generics, ty_generics, mut where_clause) =
|
||||||
cg::trait_parts(&input, trait_path);
|
cg::trait_parts(&input, trait_path);
|
||||||
|
|
||||||
|
let input_attrs = cg::parse_input_attrs::<DistanceInputAttrs>(&input);
|
||||||
let variants = cg::variants(&input);
|
let variants = cg::variants(&input);
|
||||||
let mut match_body = quote!();
|
let mut match_body = quote!();
|
||||||
let mut append_error_clause = variants.len() > 1;
|
let mut append_error_clause = variants.len() > 1;
|
||||||
match_body.append_all(variants.iter().map(|variant| {
|
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 {
|
if attrs.error {
|
||||||
append_error_clause = true;
|
append_error_clause = true;
|
||||||
return None;
|
return None;
|
||||||
|
@ -30,9 +31,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
} else {
|
} else {
|
||||||
let mut sum = quote!();
|
let mut sum = quote!();
|
||||||
sum.append_separated(this_info.iter().zip(&other_info).map(|(this, other)| {
|
sum.append_separated(this_info.iter().zip(&other_info).map(|(this, other)| {
|
||||||
where_clause.predicates.push(
|
where_clause.add_trait_bound(&this.field.ty);
|
||||||
cg::where_predicate(this.field.ty.clone(), trait_path),
|
|
||||||
);
|
|
||||||
quote! {
|
quote! {
|
||||||
::values::distance::ComputeSquaredDistance::compute_squared_distance(#this, #other)?
|
::values::distance::ComputeSquaredDistance::compute_squared_distance(#this, #other)?
|
||||||
}
|
}
|
||||||
|
@ -47,7 +46,13 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if append_error_clause {
|
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! {
|
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>,
|
||||||
|
}
|
||||||
|
|
|
@ -19,11 +19,10 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
None => return Some(quote!(false)),
|
None => return Some(quote!(false)),
|
||||||
Some(pair) => pair,
|
Some(pair) => pair,
|
||||||
};
|
};
|
||||||
|
where_clause.add_trait_bound(&first.field.ty);
|
||||||
let mut expr = quote!(::style_traits::HasViewportPercentage::has_viewport_percentage(#first));
|
let mut expr = quote!(::style_traits::HasViewportPercentage::has_viewport_percentage(#first));
|
||||||
for binding in rest {
|
for binding in rest {
|
||||||
where_clause.predicates.push(
|
where_clause.add_trait_bound(&binding.field.ty);
|
||||||
cg::where_predicate(binding.field.ty.clone(), trait_path),
|
|
||||||
);
|
|
||||||
expr = quote!(#expr || ::style_traits::HasViewportPercentage::has_viewport_percentage(#binding));
|
expr = quote!(#expr || ::style_traits::HasViewportPercentage::has_viewport_percentage(#binding));
|
||||||
}
|
}
|
||||||
Some(expr)
|
Some(expr)
|
||||||
|
|
|
@ -19,13 +19,13 @@ mod to_animated_zero;
|
||||||
mod to_computed_value;
|
mod to_computed_value;
|
||||||
mod to_css;
|
mod to_css;
|
||||||
|
|
||||||
#[proc_macro_derive(Animate, attributes(animation))]
|
#[proc_macro_derive(Animate, attributes(animate, animation))]
|
||||||
pub fn derive_animate(stream: TokenStream) -> TokenStream {
|
pub fn derive_animate(stream: TokenStream) -> TokenStream {
|
||||||
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
|
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
|
||||||
animate::derive(input).to_string().parse().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 {
|
pub fn derive_compute_squared_distance(stream: TokenStream) -> TokenStream {
|
||||||
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
|
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
|
||||||
compute_squared_distance::derive(input).to_string().parse().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()
|
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 {
|
pub fn derive_to_animated_zero(stream: TokenStream) -> TokenStream {
|
||||||
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
|
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
|
||||||
to_animated_zero::derive(input).to_string().parse().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 {
|
pub fn derive_to_computed_value(stream: TokenStream) -> TokenStream {
|
||||||
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
|
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
|
||||||
to_computed_value::derive(input).to_string().parse().unwrap()
|
to_computed_value::derive(input).to_string().parse().unwrap()
|
||||||
|
|
|
@ -9,18 +9,16 @@ use synstructure::BindStyle;
|
||||||
|
|
||||||
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
let name = &input.ident;
|
let name = &input.ident;
|
||||||
let (impl_generics, ty_generics, where_clause, animated_value_type) =
|
let trait_path = &["values", "animated", "ToAnimatedValue"];
|
||||||
cg::fmap_trait_parts(
|
let (impl_generics, ty_generics, mut where_clause, animated_value_type) =
|
||||||
&input,
|
cg::fmap_trait_parts(&input, trait_path, "AnimatedValue");
|
||||||
&["values", "animated", "ToAnimatedValue"],
|
|
||||||
"AnimatedValue",
|
|
||||||
);
|
|
||||||
|
|
||||||
let to_body = cg::fmap_match(&input, BindStyle::Move, |field| {
|
let to_body = cg::fmap_match(&input, BindStyle::Move, |binding| {
|
||||||
quote!(::values::animated::ToAnimatedValue::to_animated_value(#field))
|
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| {
|
let from_body = cg::fmap_match(&input, BindStyle::Move, |binding| {
|
||||||
quote!(::values::animated::ToAnimatedValue::from_animated_value(#field))
|
quote!(::values::animated::ToAnimatedValue::from_animated_value(#binding))
|
||||||
});
|
});
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
|
|
|
@ -2,20 +2,51 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use animate::{AnimationVariantAttrs, AnimationFieldAttrs};
|
||||||
use cg;
|
use cg;
|
||||||
use quote;
|
use quote;
|
||||||
use syn;
|
use syn;
|
||||||
use synstructure::BindStyle;
|
use synstructure::{self, BindStyle};
|
||||||
|
|
||||||
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
let name = &input.ident;
|
let name = &input.ident;
|
||||||
let (impl_generics, ty_generics, where_clause) = cg::trait_parts(
|
let trait_path = &["values", "animated", "ToAnimatedZero"];
|
||||||
&input,
|
let (impl_generics, ty_generics, mut where_clause) =
|
||||||
&["values", "animated", "ToAnimatedZero"],
|
cg::trait_parts(&input, trait_path);
|
||||||
);
|
|
||||||
|
|
||||||
let to_body = cg::fmap_match(&input, BindStyle::Ref, |field| {
|
let bind_opts = BindStyle::Ref.into();
|
||||||
quote! { ::values::animated::ToAnimatedZero::to_animated_zero(#field)? }
|
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! {
|
quote! {
|
||||||
|
@ -23,9 +54,9 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
fn to_animated_zero(&self) -> Result<Self, ()> {
|
||||||
Ok(match *self {
|
match *self {
|
||||||
#to_body
|
#to_body
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,24 +3,43 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use cg;
|
use cg;
|
||||||
use quote;
|
use quote::Tokens;
|
||||||
use syn;
|
use syn::DeriveInput;
|
||||||
use synstructure::BindStyle;
|
use synstructure::BindStyle;
|
||||||
|
|
||||||
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
pub fn derive(input: DeriveInput) -> Tokens {
|
||||||
let name = &input.ident;
|
let name = &input.ident;
|
||||||
let (impl_generics, ty_generics, where_clause, computed_value_type) =
|
let trait_path = &["values", "computed", "ToComputedValue"];
|
||||||
cg::fmap_trait_parts(
|
let (impl_generics, ty_generics, mut where_clause, computed_value_type) =
|
||||||
&input,
|
cg::fmap_trait_parts(&input, trait_path, "ComputedValue");
|
||||||
&["values", "computed", "ToComputedValue"],
|
|
||||||
"ComputedValue",
|
|
||||||
);
|
|
||||||
|
|
||||||
let to_body = cg::fmap_match(&input, BindStyle::Ref, |field| {
|
let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| {
|
||||||
quote!(::values::computed::ToComputedValue::to_computed_value(#field, context))
|
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| {
|
let from_body = cg::fmap_match(&input, BindStyle::Ref, |binding| {
|
||||||
quote!(::values::computed::ToComputedValue::from_computed_value(#field))
|
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! {
|
quote! {
|
||||||
|
@ -44,3 +63,9 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[darling(attributes(compute), default)]
|
||||||
|
#[derive(Default, FromField)]
|
||||||
|
struct ComputedValueAttrs {
|
||||||
|
clone: bool,
|
||||||
|
}
|
||||||
|
|
|
@ -3,29 +3,26 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use cg;
|
use cg;
|
||||||
use quote;
|
use quote::Tokens;
|
||||||
use syn;
|
use syn::DeriveInput;
|
||||||
use synstructure;
|
use synstructure;
|
||||||
|
|
||||||
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
pub fn derive(input: DeriveInput) -> Tokens {
|
||||||
let name = &input.ident;
|
let name = &input.ident;
|
||||||
let trait_path = &["style_traits", "ToCss"];
|
let trait_path = &["style_traits", "ToCss"];
|
||||||
let (impl_generics, ty_generics, mut where_clause) =
|
let (impl_generics, ty_generics, mut where_clause) =
|
||||||
cg::trait_parts(&input, trait_path);
|
cg::trait_parts(&input, trait_path);
|
||||||
|
|
||||||
|
let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
|
||||||
let style = synstructure::BindStyle::Ref.into();
|
let style = synstructure::BindStyle::Ref.into();
|
||||||
let match_body = synstructure::each_variant(&input, &style, |bindings, variant| {
|
let match_body = synstructure::each_variant(&input, &style, |bindings, variant| {
|
||||||
let mut identifier = to_css_identifier(variant.ident.as_ref());
|
let mut identifier = to_css_identifier(variant.ident.as_ref());
|
||||||
let css_attrs = cg::parse_variant_attrs::<CssAttrs>(variant);
|
let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(variant);
|
||||||
let separator = if css_attrs.comma { ", " } else { " " };
|
let separator = if variant_attrs.comma { ", " } else { " " };
|
||||||
let mut expr = if !bindings.is_empty() {
|
let mut expr = if !bindings.is_empty() {
|
||||||
let mut expr = quote! {};
|
let mut expr = quote! {};
|
||||||
for binding in bindings {
|
for binding in bindings {
|
||||||
if cg::is_parameterized(&binding.field.ty, &input.generics.ty_params) {
|
where_clause.add_trait_bound(&binding.field.ty);
|
||||||
where_clause.predicates.push(
|
|
||||||
cg::where_predicate(binding.field.ty.clone(), trait_path),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
expr = quote! {
|
expr = quote! {
|
||||||
#expr
|
#expr
|
||||||
writer.item(#binding)?;
|
writer.item(#binding)?;
|
||||||
|
@ -41,7 +38,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
::std::fmt::Write::write_str(dest, #identifier)
|
::std::fmt::Write::write_str(dest, #identifier)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if css_attrs.function {
|
if variant_attrs.function {
|
||||||
identifier.push_str("(");
|
identifier.push_str("(");
|
||||||
expr = quote! {
|
expr = quote! {
|
||||||
::std::fmt::Write::write_str(dest, #identifier)?;
|
::std::fmt::Write::write_str(dest, #identifier)?;
|
||||||
|
@ -52,7 +49,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
Some(expr)
|
Some(expr)
|
||||||
});
|
});
|
||||||
|
|
||||||
quote! {
|
let mut impls = quote! {
|
||||||
impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause {
|
impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
#[inline]
|
#[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)]
|
#[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,
|
function: bool,
|
||||||
comma: bool,
|
comma: bool,
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,12 @@ use std::fmt::{self, Write};
|
||||||
/// of their name;
|
/// of their name;
|
||||||
/// * unit variants whose name starts with "Moz" or "Webkit" are prepended
|
/// * unit variants whose name starts with "Moz" or "Webkit" are prepended
|
||||||
/// with a "-";
|
/// with a "-";
|
||||||
/// * variants with fields get serialised as the space-separated serialisations
|
/// * if `#[css(comma)]` is found on a variant, its fields are separated by
|
||||||
/// of their fields.
|
/// 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 {
|
pub trait ToCss {
|
||||||
/// Serialize `self` in CSS syntax, writing to `dest`.
|
/// Serialize `self` in CSS syntax, writing to `dest`.
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: Write;
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: Write;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue