Π·Π΅ΡΠΊΠ°Π»ΠΎ ΠΈΠ· https://github.com/mozilla/gecko-dev.git
servo: Merge #17560 - Introduce ToAnimatedValue π₯ (from servo:derive-all-the-things); r=<try>
Source-Repo: https://github.com/servo/servo Source-Revision: 9a13cf6bdaa823369f29d7d0f4469087cf17ce6a --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 8e2354a1c6da7a5c78ed94e34be220fe8b8986c7
This commit is contained in:
Π ΠΎΠ΄ΠΈΡΠ΅Π»Ρ
fd512fc09d
ΠΠΎΠΌΠΌΠΈΡ
fd99f68571
|
@ -110,6 +110,7 @@ macro_rules! define_keyword_type {
|
|||
}
|
||||
|
||||
impl $crate::values::computed::ComputedValueAsSpecified for $name {}
|
||||
impl $crate::values::animated::AnimatedValueAsComputed for $name {}
|
||||
no_viewport_percentage!($name);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -31,7 +31,10 @@ use std::cmp;
|
|||
#[cfg(feature = "gecko")] use fnv::FnvHashMap;
|
||||
use style_traits::ParseError;
|
||||
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::Filter as AnimatedFilter;
|
||||
use values::animated::effects::FilterList as AnimatedFilterList;
|
||||
|
@ -408,7 +411,8 @@ impl AnimatedProperty {
|
|||
};
|
||||
% endif
|
||||
% 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
|
||||
style.mutate_${prop.style_struct.ident.strip("_")}().set_${prop.ident}(value);
|
||||
}
|
||||
|
@ -425,13 +429,21 @@ impl AnimatedProperty {
|
|||
-> AnimatedProperty {
|
||||
match *property {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
AnimatableLonghand::${prop.camel_case} => {
|
||||
AnimatedProperty::${prop.camel_case}(
|
||||
old_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}().into(),
|
||||
new_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}().into())
|
||||
}
|
||||
% endif
|
||||
% if prop.animatable:
|
||||
AnimatableLonghand::${prop.camel_case} => {
|
||||
let old_computed = old_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}();
|
||||
let new_computed = new_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}();
|
||||
AnimatedProperty::${prop.camel_case}(
|
||||
% if prop.is_animatable_with_computed_value:
|
||||
old_computed,
|
||||
new_computed,
|
||||
% else:
|
||||
old_computed.to_animated_value(),
|
||||
new_computed.to_animated_value(),
|
||||
% endif
|
||||
)
|
||||
}
|
||||
% endif
|
||||
% endfor
|
||||
}
|
||||
}
|
||||
|
@ -492,7 +504,7 @@ impl AnimationValue {
|
|||
% if prop.is_animatable_with_computed_value:
|
||||
from
|
||||
% else:
|
||||
&from.clone().into()
|
||||
&ToAnimatedValue::from_animated_value(from.clone())
|
||||
% endif
|
||||
))
|
||||
% if prop.boxed:
|
||||
|
@ -520,13 +532,14 @@ impl AnimationValue {
|
|||
longhands::system_font::resolve_system_font(sf, context);
|
||||
}
|
||||
% endif
|
||||
Some(AnimationValue::${prop.camel_case}(
|
||||
% if prop.is_animatable_with_computed_value:
|
||||
val.to_computed_value(context)
|
||||
% else:
|
||||
From::from(val.to_computed_value(context))
|
||||
% endif
|
||||
))
|
||||
let computed = val.to_computed_value(context);
|
||||
Some(AnimationValue::${prop.camel_case}(
|
||||
% if prop.is_animatable_with_computed_value:
|
||||
computed
|
||||
% else:
|
||||
computed.to_animated_value()
|
||||
% endif
|
||||
))
|
||||
},
|
||||
% endif
|
||||
% endfor
|
||||
|
@ -555,7 +568,7 @@ impl AnimationValue {
|
|||
},
|
||||
};
|
||||
% if not prop.is_animatable_with_computed_value:
|
||||
let computed = From::from(computed);
|
||||
let computed = computed.to_animated_value();
|
||||
% endif
|
||||
Some(AnimationValue::${prop.camel_case}(computed))
|
||||
},
|
||||
|
@ -617,13 +630,16 @@ impl AnimationValue {
|
|||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
AnimatableLonghand::${prop.camel_case} => {
|
||||
let computed = computed_values
|
||||
.get_${prop.style_struct.ident.strip("_")}()
|
||||
.clone_${prop.ident}();
|
||||
AnimationValue::${prop.camel_case}(
|
||||
% if prop.is_animatable_with_computed_value:
|
||||
computed_values.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}())
|
||||
computed
|
||||
% else:
|
||||
From::from(computed_values.get_${prop.style_struct.ident.strip("_")}()
|
||||
.clone_${prop.ident}()))
|
||||
computed.to_animated_value()
|
||||
% endif
|
||||
)
|
||||
}
|
||||
% endif
|
||||
% 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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
/// 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.
|
||||
impl Animatable for IntermediateRGBA {
|
||||
#[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)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[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 {
|
||||
#[inline]
|
||||
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
|
||||
pub type IntermediateSVGPaint = SVGPaint<IntermediateRGBA>;
|
||||
|
||||
/// Animatable SVGPaintKind
|
||||
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 {
|
||||
#[inline]
|
||||
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;
|
||||
#[cfg(not(feature = "gecko"))]
|
||||
use values::Impossible;
|
||||
use values::animated::ToAnimatedValue;
|
||||
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::generics::effects::BoxShadow as GenericBoxShadow;
|
||||
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.
|
||||
pub type SimpleShadow = GenericSimpleShadow<IntermediateColor, Length, Length>;
|
||||
|
||||
impl From<BoxShadowList> for ComputedBoxShadowList {
|
||||
fn from(list: BoxShadowList) -> Self {
|
||||
ComputedBoxShadowList(list.0.into_iter().map(|s| s.into()).collect())
|
||||
}
|
||||
}
|
||||
impl ToAnimatedValue for ComputedBoxShadowList {
|
||||
type AnimatedValue = BoxShadowList;
|
||||
|
||||
impl From<ComputedBoxShadowList> for BoxShadowList {
|
||||
fn from(list: ComputedBoxShadowList) -> Self {
|
||||
BoxShadowList(list.0.into_iter().map(|s| s.into()).collect())
|
||||
#[inline]
|
||||
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||
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 {
|
||||
fn from(list: TextShadowList) -> Self {
|
||||
ComputedTextShadowList(list.0.into_iter().map(|s| s.into()).collect())
|
||||
}
|
||||
}
|
||||
impl ToAnimatedValue for ComputedTextShadowList {
|
||||
type AnimatedValue = TextShadowList;
|
||||
|
||||
impl From<ComputedTextShadowList> for TextShadowList {
|
||||
fn from(list: ComputedTextShadowList) -> Self {
|
||||
TextShadowList(list.0.into_iter().map(|s| s.into()).collect())
|
||||
#[inline]
|
||||
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||
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 {
|
||||
#[inline]
|
||||
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"))]
|
||||
#[inline]
|
||||
fn from(filters: ComputedFilterList) -> Self {
|
||||
FilterList(filters.0)
|
||||
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||
FilterList(self.0)
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
#[inline]
|
||||
fn from(filters: ComputedFilterList) -> Self {
|
||||
FilterList(filters.0.into_iter().map(|f| f.into()).collect())
|
||||
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||
FilterList(self.0.to_animated_value())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FilterList> for ComputedFilterList {
|
||||
#[cfg(not(feature = "gecko"))]
|
||||
#[inline]
|
||||
fn from(filters: FilterList) -> Self {
|
||||
ComputedFilterList(filters.0)
|
||||
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||
ComputedFilterList(animated.0)
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
#[inline]
|
||||
fn from(filters: FilterList) -> Self {
|
||||
ComputedFilterList(filters.0.into_iter().map(|f| f.into()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[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,
|
||||
}
|
||||
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||
ComputedFilterList(ToAnimatedValue::from_animated_value(animated.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,4 +8,83 @@
|
|||
//! computed values and need yet another intermediate representation. This
|
||||
//! 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;
|
||||
|
||||
/// 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`.
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
|
||||
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)]
|
||||
pub struct BoxShadow<Color, SizeLength, ShapeLength> {
|
||||
/// The base shadow.
|
||||
pub base: SimpleShadow<Color, SizeLength, ShapeLength>,
|
||||
|
@ -23,7 +23,7 @@ pub struct BoxShadow<Color, SizeLength, ShapeLength> {
|
|||
|
||||
/// A generic value for a single `filter`.
|
||||
#[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> {
|
||||
/// `blur(<length>)`
|
||||
#[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
|
||||
/// first, like in Gecko and Webkit.
|
||||
#[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> {
|
||||
/// Color.
|
||||
pub color: Color,
|
||||
|
|
|
@ -254,8 +254,8 @@ impl ToCss for FontSettingTagFloat {
|
|||
/// An SVG paint value
|
||||
///
|
||||
/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Clone, Debug, PartialEq, ToAnimatedValue)]
|
||||
pub struct SVGPaint<ColorType> {
|
||||
/// The paint source
|
||||
pub kind: SVGPaintKind<ColorType>,
|
||||
|
@ -269,7 +269,7 @@ pub struct SVGPaint<ColorType> {
|
|||
/// to have a fallback, Gecko lets the context
|
||||
/// properties have a fallback as well.
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[derive(Clone, Debug, PartialEq, ToCss)]
|
||||
#[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToCss)]
|
||||
pub enum SVGPaintKind<ColorType> {
|
||||
/// `none`
|
||||
None,
|
||||
|
|
|
@ -52,7 +52,7 @@ impl Parse for Impossible {
|
|||
|
||||
/// A struct representing one of two kinds of values.
|
||||
#[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> {
|
||||
/// The first value.
|
||||
First(A),
|
||||
|
|
|
@ -10,6 +10,7 @@ extern crate synstructure;
|
|||
use proc_macro::TokenStream;
|
||||
|
||||
mod has_viewport_percentage;
|
||||
mod to_animated_value;
|
||||
mod to_computed_value;
|
||||
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()
|
||||
}
|
||||
|
||||
#[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)]
|
||||
pub fn derive_to_computed_value(stream: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
|
||||
|
|
|
@ -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::longhands::transform::computed_value::ComputedOperation as TransformOperation;
|
||||
use style::properties::longhands::transform::computed_value::T as TransformList;
|
||||
use style::values::animated::ToAnimatedValue;
|
||||
use style::values::specified::length::Percentage;
|
||||
|
||||
fn interpolate_rgba(from: RGBA, to: RGBA, progress: f64) -> RGBA {
|
||||
let from: IntermediateRGBA = from.into();
|
||||
let to: IntermediateRGBA = to.into();
|
||||
from.interpolate(&to, progress).unwrap().into()
|
||||
let from = from.to_animated_value();
|
||||
let to = to.to_animated_value();
|
||||
RGBA::from_animated_value(from.interpolate(&to, progress).unwrap())
|
||||
}
|
||||
|
||||
// Color
|
||||
|
|
ΠΠ°Π³ΡΡΠ·ΠΊΠ°β¦
Π‘ΡΡΠ»ΠΊΠ° Π² Π½ΠΎΠ²ΠΎΠΉ Π·Π°Π΄Π°ΡΠ΅