mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Auto merge of #17560 - servo:derive-all-the-things, r=<try>
Introduce ToAnimatedValue 🎥 <!-- 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/17560) <!-- Reviewable:end -->
This commit is contained in:
commit
9a13cf6bda
10 changed files with 354 additions and 219 deletions
|
@ -110,6 +110,7 @@ macro_rules! define_keyword_type {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $crate::values::computed::ComputedValueAsSpecified for $name {}
|
impl $crate::values::computed::ComputedValueAsSpecified for $name {}
|
||||||
|
impl $crate::values::animated::AnimatedValueAsComputed for $name {}
|
||||||
no_viewport_percentage!($name);
|
no_viewport_percentage!($name);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,10 @@ use std::cmp;
|
||||||
#[cfg(feature = "gecko")] use fnv::FnvHashMap;
|
#[cfg(feature = "gecko")] use fnv::FnvHashMap;
|
||||||
use style_traits::ParseError;
|
use style_traits::ParseError;
|
||||||
use super::ComputedValues;
|
use super::ComputedValues;
|
||||||
use values::{Auto, CSSFloat, CustomIdent, Either};
|
#[cfg(any(feature = "gecko", feature = "testing"))]
|
||||||
|
use values::Auto;
|
||||||
|
use values::{CSSFloat, CustomIdent, Either};
|
||||||
|
use values::animated::ToAnimatedValue;
|
||||||
use values::animated::effects::BoxShadowList as AnimatedBoxShadowList;
|
use values::animated::effects::BoxShadowList as AnimatedBoxShadowList;
|
||||||
use values::animated::effects::Filter as AnimatedFilter;
|
use values::animated::effects::Filter as AnimatedFilter;
|
||||||
use values::animated::effects::FilterList as AnimatedFilterList;
|
use values::animated::effects::FilterList as AnimatedFilterList;
|
||||||
|
@ -408,7 +411,8 @@ impl AnimatedProperty {
|
||||||
};
|
};
|
||||||
% endif
|
% endif
|
||||||
% if not prop.is_animatable_with_computed_value:
|
% if not prop.is_animatable_with_computed_value:
|
||||||
let value: longhands::${prop.ident}::computed_value::T = value.into();
|
let value: longhands::${prop.ident}::computed_value::T =
|
||||||
|
ToAnimatedValue::from_animated_value(value);
|
||||||
% endif
|
% endif
|
||||||
style.mutate_${prop.style_struct.ident.strip("_")}().set_${prop.ident}(value);
|
style.mutate_${prop.style_struct.ident.strip("_")}().set_${prop.ident}(value);
|
||||||
}
|
}
|
||||||
|
@ -425,13 +429,21 @@ impl AnimatedProperty {
|
||||||
-> AnimatedProperty {
|
-> AnimatedProperty {
|
||||||
match *property {
|
match *property {
|
||||||
% for prop in data.longhands:
|
% for prop in data.longhands:
|
||||||
% if prop.animatable:
|
% if prop.animatable:
|
||||||
AnimatableLonghand::${prop.camel_case} => {
|
AnimatableLonghand::${prop.camel_case} => {
|
||||||
AnimatedProperty::${prop.camel_case}(
|
let old_computed = old_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}();
|
||||||
old_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}().into(),
|
let new_computed = new_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}();
|
||||||
new_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}().into())
|
AnimatedProperty::${prop.camel_case}(
|
||||||
}
|
% if prop.is_animatable_with_computed_value:
|
||||||
% endif
|
old_computed,
|
||||||
|
new_computed,
|
||||||
|
% else:
|
||||||
|
old_computed.to_animated_value(),
|
||||||
|
new_computed.to_animated_value(),
|
||||||
|
% endif
|
||||||
|
)
|
||||||
|
}
|
||||||
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -492,7 +504,7 @@ impl AnimationValue {
|
||||||
% if prop.is_animatable_with_computed_value:
|
% if prop.is_animatable_with_computed_value:
|
||||||
from
|
from
|
||||||
% else:
|
% else:
|
||||||
&from.clone().into()
|
&ToAnimatedValue::from_animated_value(from.clone())
|
||||||
% endif
|
% endif
|
||||||
))
|
))
|
||||||
% if prop.boxed:
|
% if prop.boxed:
|
||||||
|
@ -520,13 +532,14 @@ impl AnimationValue {
|
||||||
longhands::system_font::resolve_system_font(sf, context);
|
longhands::system_font::resolve_system_font(sf, context);
|
||||||
}
|
}
|
||||||
% endif
|
% endif
|
||||||
Some(AnimationValue::${prop.camel_case}(
|
let computed = val.to_computed_value(context);
|
||||||
% if prop.is_animatable_with_computed_value:
|
Some(AnimationValue::${prop.camel_case}(
|
||||||
val.to_computed_value(context)
|
% if prop.is_animatable_with_computed_value:
|
||||||
% else:
|
computed
|
||||||
From::from(val.to_computed_value(context))
|
% else:
|
||||||
% endif
|
computed.to_animated_value()
|
||||||
))
|
% endif
|
||||||
|
))
|
||||||
},
|
},
|
||||||
% endif
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
|
@ -555,7 +568,7 @@ impl AnimationValue {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
% if not prop.is_animatable_with_computed_value:
|
% if not prop.is_animatable_with_computed_value:
|
||||||
let computed = From::from(computed);
|
let computed = computed.to_animated_value();
|
||||||
% endif
|
% endif
|
||||||
Some(AnimationValue::${prop.camel_case}(computed))
|
Some(AnimationValue::${prop.camel_case}(computed))
|
||||||
},
|
},
|
||||||
|
@ -617,13 +630,16 @@ impl AnimationValue {
|
||||||
% for prop in data.longhands:
|
% for prop in data.longhands:
|
||||||
% if prop.animatable:
|
% if prop.animatable:
|
||||||
AnimatableLonghand::${prop.camel_case} => {
|
AnimatableLonghand::${prop.camel_case} => {
|
||||||
|
let computed = computed_values
|
||||||
|
.get_${prop.style_struct.ident.strip("_")}()
|
||||||
|
.clone_${prop.ident}();
|
||||||
AnimationValue::${prop.camel_case}(
|
AnimationValue::${prop.camel_case}(
|
||||||
% if prop.is_animatable_with_computed_value:
|
% if prop.is_animatable_with_computed_value:
|
||||||
computed_values.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}())
|
computed
|
||||||
% else:
|
% else:
|
||||||
From::from(computed_values.get_${prop.style_struct.ident.strip("_")}()
|
computed.to_animated_value()
|
||||||
.clone_${prop.ident}()))
|
|
||||||
% endif
|
% endif
|
||||||
|
)
|
||||||
}
|
}
|
||||||
% endif
|
% endif
|
||||||
% endfor
|
% endfor
|
||||||
|
@ -2697,25 +2713,6 @@ impl<T, U> Animatable for Either<T, U>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IntermediateRGBA> for RGBA {
|
|
||||||
fn from(extended_rgba: IntermediateRGBA) -> RGBA {
|
|
||||||
// RGBA::from_floats clamps each component values.
|
|
||||||
RGBA::from_floats(extended_rgba.red,
|
|
||||||
extended_rgba.green,
|
|
||||||
extended_rgba.blue,
|
|
||||||
extended_rgba.alpha)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<RGBA> for IntermediateRGBA {
|
|
||||||
fn from(rgba: RGBA) -> IntermediateRGBA {
|
|
||||||
IntermediateRGBA::new(rgba.red_f32(),
|
|
||||||
rgba.green_f32(),
|
|
||||||
rgba.blue_f32(),
|
|
||||||
rgba.alpha_f32())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
/// Unlike RGBA, each component value may exceed the range [0.0, 1.0].
|
/// Unlike RGBA, each component value may exceed the range [0.0, 1.0].
|
||||||
|
@ -2744,6 +2741,31 @@ impl IntermediateRGBA {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToAnimatedValue for RGBA {
|
||||||
|
type AnimatedValue = IntermediateRGBA;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||||
|
IntermediateRGBA::new(
|
||||||
|
self.red_f32(),
|
||||||
|
self.green_f32(),
|
||||||
|
self.blue_f32(),
|
||||||
|
self.alpha_f32(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||||
|
// RGBA::from_floats clamps each component values.
|
||||||
|
RGBA::from_floats(
|
||||||
|
animated.red,
|
||||||
|
animated.green,
|
||||||
|
animated.blue,
|
||||||
|
animated.alpha,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Unlike Animatable for RGBA we don't clamp any component values.
|
/// Unlike Animatable for RGBA we don't clamp any component values.
|
||||||
impl Animatable for IntermediateRGBA {
|
impl Animatable for IntermediateRGBA {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -2798,24 +2820,6 @@ impl Animatable for IntermediateRGBA {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Either<Color, Auto>> for Either<IntermediateColor, Auto> {
|
|
||||||
fn from(from: Either<Color, Auto>) -> Either<IntermediateColor, Auto> {
|
|
||||||
match from {
|
|
||||||
Either::First(from) => Either::First(from.into()),
|
|
||||||
Either::Second(Auto) => Either::Second(Auto),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Either<IntermediateColor, Auto>> for Either<Color, Auto> {
|
|
||||||
fn from(from: Either<IntermediateColor, Auto>) -> Either<Color, Auto> {
|
|
||||||
match from {
|
|
||||||
Either::First(from) => Either::First(from.into()),
|
|
||||||
Either::Second(Auto) => Either::Second(Auto),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
|
@ -2856,6 +2860,26 @@ impl IntermediateColor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToAnimatedValue for Color {
|
||||||
|
type AnimatedValue = IntermediateColor;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||||
|
IntermediateColor {
|
||||||
|
color: self.color.to_animated_value(),
|
||||||
|
foreground_ratio: self.foreground_ratio as f32 * (1. / 255.),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||||
|
Color {
|
||||||
|
color: RGBA::from_animated_value(animated.color),
|
||||||
|
foreground_ratio: (animated.foreground_ratio * 255.).round() as u8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Animatable for IntermediateColor {
|
impl Animatable for IntermediateColor {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
|
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
|
||||||
|
@ -2934,42 +2958,12 @@ impl Animatable for IntermediateColor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Color> for IntermediateColor {
|
|
||||||
fn from(color: Color) -> IntermediateColor {
|
|
||||||
IntermediateColor {
|
|
||||||
color: color.color.into(),
|
|
||||||
foreground_ratio: color.foreground_ratio as f32 * (1. / 255.),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<IntermediateColor> for Color {
|
|
||||||
fn from(color: IntermediateColor) -> Color {
|
|
||||||
Color {
|
|
||||||
color: color.color.into(),
|
|
||||||
foreground_ratio: (color.foreground_ratio * 255.).round() as u8,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Animatable SVGPaint
|
/// Animatable SVGPaint
|
||||||
pub type IntermediateSVGPaint = SVGPaint<IntermediateRGBA>;
|
pub type IntermediateSVGPaint = SVGPaint<IntermediateRGBA>;
|
||||||
|
|
||||||
/// Animatable SVGPaintKind
|
/// Animatable SVGPaintKind
|
||||||
pub type IntermediateSVGPaintKind = SVGPaintKind<IntermediateRGBA>;
|
pub type IntermediateSVGPaintKind = SVGPaintKind<IntermediateRGBA>;
|
||||||
|
|
||||||
impl From<::values::computed::SVGPaint> for IntermediateSVGPaint {
|
|
||||||
fn from(paint: ::values::computed::SVGPaint) -> IntermediateSVGPaint {
|
|
||||||
paint.convert(|color| (*color).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<IntermediateSVGPaint> for ::values::computed::SVGPaint {
|
|
||||||
fn from(paint: IntermediateSVGPaint) -> ::values::computed::SVGPaint {
|
|
||||||
paint.convert(|color| (*color).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl Animatable for IntermediateSVGPaint {
|
impl Animatable for IntermediateSVGPaint {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
|
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
|
||||||
|
|
|
@ -12,11 +12,8 @@ use properties::longhands::text_shadow::computed_value::T as ComputedTextShadowL
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
#[cfg(not(feature = "gecko"))]
|
#[cfg(not(feature = "gecko"))]
|
||||||
use values::Impossible;
|
use values::Impossible;
|
||||||
|
use values::animated::ToAnimatedValue;
|
||||||
use values::computed::{Angle, Number};
|
use values::computed::{Angle, Number};
|
||||||
use values::computed::effects::BoxShadow as ComputedBoxShadow;
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
use values::computed::effects::Filter as ComputedFilter;
|
|
||||||
use values::computed::effects::SimpleShadow as ComputedSimpleShadow;
|
|
||||||
use values::computed::length::Length;
|
use values::computed::length::Length;
|
||||||
use values::generics::effects::BoxShadow as GenericBoxShadow;
|
use values::generics::effects::BoxShadow as GenericBoxShadow;
|
||||||
use values::generics::effects::Filter as GenericFilter;
|
use values::generics::effects::Filter as GenericFilter;
|
||||||
|
@ -51,15 +48,17 @@ pub struct TextShadowList(pub Vec<SimpleShadow>);
|
||||||
/// An animated value for the `drop-shadow()` filter.
|
/// An animated value for the `drop-shadow()` filter.
|
||||||
pub type SimpleShadow = GenericSimpleShadow<IntermediateColor, Length, Length>;
|
pub type SimpleShadow = GenericSimpleShadow<IntermediateColor, Length, Length>;
|
||||||
|
|
||||||
impl From<BoxShadowList> for ComputedBoxShadowList {
|
impl ToAnimatedValue for ComputedBoxShadowList {
|
||||||
fn from(list: BoxShadowList) -> Self {
|
type AnimatedValue = BoxShadowList;
|
||||||
ComputedBoxShadowList(list.0.into_iter().map(|s| s.into()).collect())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ComputedBoxShadowList> for BoxShadowList {
|
#[inline]
|
||||||
fn from(list: ComputedBoxShadowList) -> Self {
|
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||||
BoxShadowList(list.0.into_iter().map(|s| s.into()).collect())
|
BoxShadowList(self.0.to_animated_value())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||||
|
ComputedBoxShadowList(ToAnimatedValue::from_animated_value(animated.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,15 +113,17 @@ impl Animatable for BoxShadowList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TextShadowList> for ComputedTextShadowList {
|
impl ToAnimatedValue for ComputedTextShadowList {
|
||||||
fn from(list: TextShadowList) -> Self {
|
type AnimatedValue = TextShadowList;
|
||||||
ComputedTextShadowList(list.0.into_iter().map(|s| s.into()).collect())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ComputedTextShadowList> for TextShadowList {
|
#[inline]
|
||||||
fn from(list: ComputedTextShadowList) -> Self {
|
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||||
TextShadowList(list.0.into_iter().map(|s| s.into()).collect())
|
TextShadowList(self.0.to_animated_value())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||||
|
ComputedTextShadowList(ToAnimatedValue::from_animated_value(animated.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,28 +171,6 @@ impl Animatable for TextShadowList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ComputedBoxShadow> for BoxShadow {
|
|
||||||
#[inline]
|
|
||||||
fn from(shadow: ComputedBoxShadow) -> Self {
|
|
||||||
BoxShadow {
|
|
||||||
base: shadow.base.into(),
|
|
||||||
spread: shadow.spread,
|
|
||||||
inset: shadow.inset,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<BoxShadow> for ComputedBoxShadow {
|
|
||||||
#[inline]
|
|
||||||
fn from(shadow: BoxShadow) -> Self {
|
|
||||||
ComputedBoxShadow {
|
|
||||||
base: shadow.base.into(),
|
|
||||||
spread: shadow.spread,
|
|
||||||
inset: shadow.inset,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Animatable for BoxShadow {
|
impl Animatable for BoxShadow {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_weighted(
|
fn add_weighted(
|
||||||
|
@ -227,99 +206,32 @@ impl Animatable for BoxShadow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ComputedFilterList> for FilterList {
|
|
||||||
|
impl ToAnimatedValue for ComputedFilterList {
|
||||||
|
type AnimatedValue = FilterList;
|
||||||
|
|
||||||
#[cfg(not(feature = "gecko"))]
|
#[cfg(not(feature = "gecko"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(filters: ComputedFilterList) -> Self {
|
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||||
FilterList(filters.0)
|
FilterList(self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(filters: ComputedFilterList) -> Self {
|
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||||
FilterList(filters.0.into_iter().map(|f| f.into()).collect())
|
FilterList(self.0.to_animated_value())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl From<FilterList> for ComputedFilterList {
|
|
||||||
#[cfg(not(feature = "gecko"))]
|
#[cfg(not(feature = "gecko"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(filters: FilterList) -> Self {
|
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||||
ComputedFilterList(filters.0)
|
ComputedFilterList(animated.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(filters: FilterList) -> Self {
|
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||||
ComputedFilterList(filters.0.into_iter().map(|f| f.into()).collect())
|
ComputedFilterList(ToAnimatedValue::from_animated_value(animated.0))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
impl From<ComputedFilter> for Filter {
|
|
||||||
#[inline]
|
|
||||||
fn from(filter: ComputedFilter) -> Self {
|
|
||||||
match filter {
|
|
||||||
GenericFilter::Blur(angle) => GenericFilter::Blur(angle),
|
|
||||||
GenericFilter::Brightness(factor) => GenericFilter::Brightness(factor),
|
|
||||||
GenericFilter::Contrast(factor) => GenericFilter::Contrast(factor),
|
|
||||||
GenericFilter::Grayscale(factor) => GenericFilter::Grayscale(factor),
|
|
||||||
GenericFilter::HueRotate(factor) => GenericFilter::HueRotate(factor),
|
|
||||||
GenericFilter::Invert(factor) => GenericFilter::Invert(factor),
|
|
||||||
GenericFilter::Opacity(factor) => GenericFilter::Opacity(factor),
|
|
||||||
GenericFilter::Saturate(factor) => GenericFilter::Saturate(factor),
|
|
||||||
GenericFilter::Sepia(factor) => GenericFilter::Sepia(factor),
|
|
||||||
GenericFilter::DropShadow(shadow) => {
|
|
||||||
GenericFilter::DropShadow(shadow.into())
|
|
||||||
},
|
|
||||||
GenericFilter::Url(url) => GenericFilter::Url(url),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
impl From<Filter> for ComputedFilter {
|
|
||||||
#[inline]
|
|
||||||
fn from(filter: Filter) -> Self {
|
|
||||||
match filter {
|
|
||||||
GenericFilter::Blur(angle) => GenericFilter::Blur(angle),
|
|
||||||
GenericFilter::Brightness(factor) => GenericFilter::Brightness(factor),
|
|
||||||
GenericFilter::Contrast(factor) => GenericFilter::Contrast(factor),
|
|
||||||
GenericFilter::Grayscale(factor) => GenericFilter::Grayscale(factor),
|
|
||||||
GenericFilter::HueRotate(factor) => GenericFilter::HueRotate(factor),
|
|
||||||
GenericFilter::Invert(factor) => GenericFilter::Invert(factor),
|
|
||||||
GenericFilter::Opacity(factor) => GenericFilter::Opacity(factor),
|
|
||||||
GenericFilter::Saturate(factor) => GenericFilter::Saturate(factor),
|
|
||||||
GenericFilter::Sepia(factor) => GenericFilter::Sepia(factor),
|
|
||||||
GenericFilter::DropShadow(shadow) => {
|
|
||||||
GenericFilter::DropShadow(shadow.into())
|
|
||||||
},
|
|
||||||
GenericFilter::Url(url) => GenericFilter::Url(url.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ComputedSimpleShadow> for SimpleShadow {
|
|
||||||
#[inline]
|
|
||||||
fn from(shadow: ComputedSimpleShadow) -> Self {
|
|
||||||
SimpleShadow {
|
|
||||||
color: shadow.color.into(),
|
|
||||||
horizontal: shadow.horizontal,
|
|
||||||
vertical: shadow.vertical,
|
|
||||||
blur: shadow.blur,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<SimpleShadow> for ComputedSimpleShadow {
|
|
||||||
#[inline]
|
|
||||||
fn from(shadow: SimpleShadow) -> Self {
|
|
||||||
ComputedSimpleShadow {
|
|
||||||
color: shadow.color.into(),
|
|
||||||
horizontal: shadow.horizontal,
|
|
||||||
vertical: shadow.vertical,
|
|
||||||
blur: shadow.blur,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,4 +8,83 @@
|
||||||
//! computed values and need yet another intermediate representation. This
|
//! computed values and need yet another intermediate representation. This
|
||||||
//! module's raison d'être is to ultimately contain all these types.
|
//! module's raison d'être is to ultimately contain all these types.
|
||||||
|
|
||||||
|
use app_units::Au;
|
||||||
|
use values::computed::Angle as ComputedAngle;
|
||||||
|
use values::specified::url::SpecifiedUrl;
|
||||||
|
|
||||||
pub mod effects;
|
pub mod effects;
|
||||||
|
|
||||||
|
/// Conversion between computed values and intermediate values for animations.
|
||||||
|
///
|
||||||
|
/// Notably, colors are represented as four floats during animations.
|
||||||
|
pub trait ToAnimatedValue {
|
||||||
|
/// The type of the animated value.
|
||||||
|
type AnimatedValue;
|
||||||
|
|
||||||
|
/// Converts this value to an animated value.
|
||||||
|
fn to_animated_value(self) -> Self::AnimatedValue;
|
||||||
|
|
||||||
|
/// Converts back an animated value into a computed value.
|
||||||
|
fn from_animated_value(animated: Self::AnimatedValue) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ToAnimatedValue for Option<T>
|
||||||
|
where
|
||||||
|
T: ToAnimatedValue,
|
||||||
|
{
|
||||||
|
type AnimatedValue = Option<<T as ToAnimatedValue>::AnimatedValue>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||||
|
self.map(T::to_animated_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||||
|
animated.map(T::from_animated_value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ToAnimatedValue for Vec<T>
|
||||||
|
where
|
||||||
|
T: ToAnimatedValue,
|
||||||
|
{
|
||||||
|
type AnimatedValue = Vec<<T as ToAnimatedValue>::AnimatedValue>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||||
|
self.into_iter().map(T::to_animated_value).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||||
|
animated.into_iter().map(T::from_animated_value).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marker trait for computed values with the same representation during animations.
|
||||||
|
pub trait AnimatedValueAsComputed {}
|
||||||
|
|
||||||
|
impl AnimatedValueAsComputed for Au {}
|
||||||
|
impl AnimatedValueAsComputed for ComputedAngle {}
|
||||||
|
impl AnimatedValueAsComputed for SpecifiedUrl {}
|
||||||
|
impl AnimatedValueAsComputed for bool {}
|
||||||
|
impl AnimatedValueAsComputed for f32 {}
|
||||||
|
|
||||||
|
impl<T> ToAnimatedValue for T
|
||||||
|
where
|
||||||
|
T: AnimatedValueAsComputed,
|
||||||
|
{
|
||||||
|
type AnimatedValue = Self;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_animated_value(self) -> Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||||
|
animated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ 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)]
|
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)]
|
||||||
pub struct BoxShadow<Color, SizeLength, ShapeLength> {
|
pub struct BoxShadow<Color, SizeLength, ShapeLength> {
|
||||||
/// The base shadow.
|
/// The base shadow.
|
||||||
pub base: SimpleShadow<Color, SizeLength, ShapeLength>,
|
pub base: SimpleShadow<Color, SizeLength, ShapeLength>,
|
||||||
|
@ -23,7 +23,7 @@ pub struct BoxShadow<Color, SizeLength, ShapeLength> {
|
||||||
|
|
||||||
/// A generic value for a single `filter`.
|
/// A generic value for a single `filter`.
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, HeapSizeOf, Serialize))]
|
#[cfg_attr(feature = "servo", derive(Deserialize, HeapSizeOf, Serialize))]
|
||||||
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)]
|
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)]
|
||||||
pub enum Filter<Angle, Factor, Length, DropShadow> {
|
pub enum Filter<Angle, Factor, Length, DropShadow> {
|
||||||
/// `blur(<length>)`
|
/// `blur(<length>)`
|
||||||
#[css(function)]
|
#[css(function)]
|
||||||
|
@ -65,7 +65,7 @@ pub enum Filter<Angle, Factor, Length, DropShadow> {
|
||||||
/// Contrary to the canonical order from the spec, the color is serialised
|
/// Contrary to the canonical order from the spec, the color is serialised
|
||||||
/// first, like in Gecko and Webkit.
|
/// first, like in Gecko and Webkit.
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
|
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue, ToCss)]
|
||||||
pub struct SimpleShadow<Color, SizeLength, ShapeLength> {
|
pub struct SimpleShadow<Color, SizeLength, ShapeLength> {
|
||||||
/// Color.
|
/// Color.
|
||||||
pub color: Color,
|
pub color: Color,
|
||||||
|
|
|
@ -254,8 +254,8 @@ impl ToCss for FontSettingTagFloat {
|
||||||
/// An SVG paint value
|
/// An SVG paint value
|
||||||
///
|
///
|
||||||
/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
|
/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[derive(Clone, Debug, PartialEq, ToAnimatedValue)]
|
||||||
pub struct SVGPaint<ColorType> {
|
pub struct SVGPaint<ColorType> {
|
||||||
/// The paint source
|
/// The paint source
|
||||||
pub kind: SVGPaintKind<ColorType>,
|
pub kind: SVGPaintKind<ColorType>,
|
||||||
|
@ -269,7 +269,7 @@ pub struct SVGPaint<ColorType> {
|
||||||
/// 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, ToCss)]
|
#[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToCss)]
|
||||||
pub enum SVGPaintKind<ColorType> {
|
pub enum SVGPaintKind<ColorType> {
|
||||||
/// `none`
|
/// `none`
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -52,7 +52,7 @@ impl Parse for Impossible {
|
||||||
|
|
||||||
/// A struct representing one of two kinds of values.
|
/// A struct representing one of two kinds of values.
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[derive(Clone, Copy, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)]
|
#[derive(Clone, Copy, HasViewportPercentage, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)]
|
||||||
pub enum Either<A, B> {
|
pub enum Either<A, B> {
|
||||||
/// The first value.
|
/// The first value.
|
||||||
First(A),
|
First(A),
|
||||||
|
|
|
@ -10,6 +10,7 @@ extern crate synstructure;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
mod has_viewport_percentage;
|
mod has_viewport_percentage;
|
||||||
|
mod to_animated_value;
|
||||||
mod to_computed_value;
|
mod to_computed_value;
|
||||||
mod to_css;
|
mod to_css;
|
||||||
|
|
||||||
|
@ -19,6 +20,12 @@ pub fn derive_has_viewport_percentage(stream: TokenStream) -> TokenStream {
|
||||||
has_viewport_percentage::derive(input).to_string().parse().unwrap()
|
has_viewport_percentage::derive(input).to_string().parse().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(ToAnimatedValue)]
|
||||||
|
pub fn derive_to_animated_value(stream: TokenStream) -> TokenStream {
|
||||||
|
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
|
||||||
|
to_animated_value::derive(input).to_string().parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(ToComputedValue)]
|
#[proc_macro_derive(ToComputedValue)]
|
||||||
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();
|
||||||
|
|
141
components/style_derive/to_animated_value.rs
Normal file
141
components/style_derive/to_animated_value.rs
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use quote;
|
||||||
|
use syn;
|
||||||
|
use synstructure;
|
||||||
|
|
||||||
|
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
|
||||||
|
let name = &input.ident;
|
||||||
|
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(where_predicate(syn::Ty::Path(None, param.ident.clone().into()), None));
|
||||||
|
}
|
||||||
|
|
||||||
|
let animated_value_type = syn::Path::from(syn::PathSegment {
|
||||||
|
ident: name.clone(),
|
||||||
|
parameters: syn::PathParameters::AngleBracketed(syn::AngleBracketedParameterData {
|
||||||
|
lifetimes: input.generics.lifetimes.iter().map(|l| {
|
||||||
|
l.lifetime.clone()
|
||||||
|
}).collect(),
|
||||||
|
types: input.generics.ty_params.iter().map(|ty| {
|
||||||
|
syn::Ty::Path(
|
||||||
|
Some(syn::QSelf {
|
||||||
|
ty: Box::new(syn::Ty::Path(None, ty.ident.clone().into())),
|
||||||
|
position: 3,
|
||||||
|
}),
|
||||||
|
syn::Path {
|
||||||
|
global: true,
|
||||||
|
segments: vec![
|
||||||
|
"values".into(),
|
||||||
|
"animated".into(),
|
||||||
|
"ToAnimatedValue".into(),
|
||||||
|
"AnimatedValue".into(),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}).collect(),
|
||||||
|
.. Default::default()
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
let to_body = match_body(&input, |field| {
|
||||||
|
quote!(::values::animated::ToAnimatedValue::to_animated_value(#field))
|
||||||
|
});
|
||||||
|
let from_body = match_body(&input, |field| {
|
||||||
|
quote!(::values::animated::ToAnimatedValue::from_animated_value(#field))
|
||||||
|
});
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
impl #impl_generics ::values::animated::ToAnimatedValue for #name #ty_generics #where_clause {
|
||||||
|
type AnimatedValue = #animated_value_type;
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
#[inline]
|
||||||
|
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||||
|
match self {
|
||||||
|
#to_body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||||
|
match animated {
|
||||||
|
#from_body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_body<F>(input: &syn::DeriveInput, f: F) -> quote::Tokens
|
||||||
|
where
|
||||||
|
F: Fn(&synstructure::BindingInfo) -> quote::Tokens,
|
||||||
|
{
|
||||||
|
let by_value = synstructure::BindStyle::Move.into();
|
||||||
|
synstructure::each_variant(&input, &by_value, |fields, variant| {
|
||||||
|
let name = if let syn::Body::Enum(_) = input.body {
|
||||||
|
format!("{}::{}", input.ident, variant.ident).into()
|
||||||
|
} else {
|
||||||
|
variant.ident.clone()
|
||||||
|
};
|
||||||
|
let (animated_value, computed_fields) = synstructure::match_pattern(&name, &variant.data, &by_value);
|
||||||
|
let fields_pairs = fields.iter().zip(computed_fields.iter());
|
||||||
|
let mut computations = quote!();
|
||||||
|
computations.append_all(fields_pairs.map(|(field, computed_field)| {
|
||||||
|
let expr = f(field);
|
||||||
|
quote!(let #computed_field = #expr;)
|
||||||
|
}));
|
||||||
|
Some(quote!(
|
||||||
|
#computations
|
||||||
|
#animated_value
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `#ty: ::values::animated::ToAnimatedValue<AnimatedValue = #animated_value,>`
|
||||||
|
fn where_predicate(ty: syn::Ty, animated_value: Option<syn::Ty>) -> syn::WherePredicate {
|
||||||
|
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
|
||||||
|
bound_lifetimes: vec![],
|
||||||
|
bounded_ty: ty,
|
||||||
|
bounds: vec![syn::TyParamBound::Trait(
|
||||||
|
syn::PolyTraitRef {
|
||||||
|
bound_lifetimes: vec![],
|
||||||
|
trait_ref: trait_ref(animated_value),
|
||||||
|
},
|
||||||
|
syn::TraitBoundModifier::None
|
||||||
|
)],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `::values::animated::ToAnimatedValue<AnimatedValue = #animated_value,>`
|
||||||
|
fn trait_ref(animated_value: Option<syn::Ty>) -> syn::Path {
|
||||||
|
syn::Path {
|
||||||
|
global: true,
|
||||||
|
segments: vec![
|
||||||
|
"values".into(),
|
||||||
|
"animated".into(),
|
||||||
|
syn::PathSegment {
|
||||||
|
ident: "ToAnimatedValue".into(),
|
||||||
|
parameters: syn::PathParameters::AngleBracketed(
|
||||||
|
syn::AngleBracketedParameterData {
|
||||||
|
bindings: trait_bindings(animated_value),
|
||||||
|
.. Default::default()
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `AnimatedValue = #animated_value,`
|
||||||
|
fn trait_bindings(animated_value: Option<syn::Ty>) -> Vec<syn::TypeBinding> {
|
||||||
|
animated_value.into_iter().map(|ty| {
|
||||||
|
syn::TypeBinding {
|
||||||
|
ident: "AnimatedValue".into(),
|
||||||
|
ty: ty,
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
|
}
|
|
@ -7,12 +7,13 @@ use cssparser::RGBA;
|
||||||
use style::properties::animated_properties::{Animatable, IntermediateRGBA};
|
use style::properties::animated_properties::{Animatable, IntermediateRGBA};
|
||||||
use style::properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
|
use style::properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
|
||||||
use style::properties::longhands::transform::computed_value::T as TransformList;
|
use style::properties::longhands::transform::computed_value::T as TransformList;
|
||||||
|
use style::values::animated::ToAnimatedValue;
|
||||||
use style::values::specified::length::Percentage;
|
use style::values::specified::length::Percentage;
|
||||||
|
|
||||||
fn interpolate_rgba(from: RGBA, to: RGBA, progress: f64) -> RGBA {
|
fn interpolate_rgba(from: RGBA, to: RGBA, progress: f64) -> RGBA {
|
||||||
let from: IntermediateRGBA = from.into();
|
let from = from.to_animated_value();
|
||||||
let to: IntermediateRGBA = to.into();
|
let to = to.to_animated_value();
|
||||||
from.interpolate(&to, progress).unwrap().into()
|
RGBA::from_animated_value(from.interpolate(&to, progress).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Color
|
// Color
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue