diff --git a/components/style/values/animated/effects.rs b/components/style/values/animated/effects.rs index 49e751fec55..2a073062fc7 100644 --- a/components/style/values/animated/effects.rs +++ b/components/style/values/animated/effects.rs @@ -19,8 +19,8 @@ pub type AnimatedSimpleShadow = GenericSimpleShadow; /// An animated value for a single `filter`. #[cfg(feature = "gecko")] -pub type AnimatedFilter = GenericFilter; +pub type AnimatedFilter = GenericFilter; /// An animated value for a single `filter`. #[cfg(not(feature = "gecko"))] -pub type AnimatedFilter = GenericFilter; +pub type AnimatedFilter = GenericFilter; diff --git a/components/style/values/computed/effects.rs b/components/style/values/computed/effects.rs index 24ec689e49c..bac58cf93ab 100644 --- a/components/style/values/computed/effects.rs +++ b/components/style/values/computed/effects.rs @@ -8,7 +8,7 @@ use crate::values::computed::color::Color; use crate::values::computed::length::{Length, NonNegativeLength}; #[cfg(feature = "gecko")] use crate::values::computed::url::ComputedUrl; -use crate::values::computed::{Angle, NonNegativeNumber}; +use crate::values::computed::{Angle, ZeroToOneNumber, NonNegativeNumber}; use crate::values::generics::effects::BoxShadow as GenericBoxShadow; use crate::values::generics::effects::Filter as GenericFilter; use crate::values::generics::effects::SimpleShadow as GenericSimpleShadow; @@ -21,12 +21,12 @@ pub type BoxShadow = GenericBoxShadow; /// A computed value for a single `filter`. #[cfg(feature = "gecko")] pub type Filter = - GenericFilter; + GenericFilter; /// A computed value for a single `filter`. #[cfg(feature = "servo")] pub type Filter = - GenericFilter; + GenericFilter; /// A computed value for the `drop-shadow()` filter. pub type SimpleShadow = GenericSimpleShadow; diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index f9711947673..999596c25f7 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -10,7 +10,7 @@ use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth}; use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize}; use super::generics::transform::IsParallelTo; -use super::generics::{self, GreaterThanOrEqualToOne, NonNegative}; +use super::generics::{self, GreaterThanOrEqualToOne, NonNegative, ZeroToOne}; use super::specified; use super::{CSSFloat, CSSInteger}; use crate::context::QuirksMode; @@ -519,6 +519,30 @@ impl From for CSSFloat { } } +/// A wrapper of Number, but the value between 0 and 1 +pub type ZeroToOneNumber = ZeroToOne; + +impl ToAnimatedValue for ZeroToOneNumber { + type AnimatedValue = CSSFloat; + + #[inline] + fn to_animated_value(self) -> Self::AnimatedValue { + self.0 + } + + #[inline] + fn from_animated_value(animated: Self::AnimatedValue) -> Self { + Self(animated.max(0.).min(1.)) + } +} + +impl From for ZeroToOneNumber { + #[inline] + fn from(number: CSSFloat) -> Self { + Self(number) + } +} + /// A wrapper of Number, but the value >= 1. pub type GreaterThanOrEqualToOneNumber = GreaterThanOrEqualToOne; diff --git a/components/style/values/generics/effects.rs b/components/style/values/generics/effects.rs index beca716e997..724f484f283 100644 --- a/components/style/values/generics/effects.rs +++ b/components/style/values/generics/effects.rs @@ -52,34 +52,34 @@ pub use self::GenericBoxShadow as BoxShadow; ToShmem, )] #[repr(C, u8)] -pub enum GenericFilter { +pub enum GenericFilter { /// `blur()` #[css(function)] Blur(Length), /// `brightness()` #[css(function)] - Brightness(Factor), + Brightness(NonNegativeFactor), /// `contrast()` #[css(function)] - Contrast(Factor), + Contrast(NonNegativeFactor), /// `grayscale()` #[css(function)] - Grayscale(Factor), + Grayscale(ZeroToOneFactor), /// `hue-rotate()` #[css(function)] HueRotate(Angle), /// `invert()` #[css(function)] - Invert(Factor), + Invert(ZeroToOneFactor), /// `opacity()` #[css(function)] - Opacity(Factor), + Opacity(ZeroToOneFactor), /// `saturate()` #[css(function)] - Saturate(Factor), + Saturate(NonNegativeFactor), /// `sepia()` #[css(function)] - Sepia(Factor), + Sepia(ZeroToOneFactor), /// `drop-shadow(...)` #[css(function)] DropShadow(Shadow), diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index 08ae15a4c2c..9989feec096 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -227,6 +227,28 @@ impl Zero for NonNegative { )] pub struct GreaterThanOrEqualToOne(pub T); +/// A wrapper of values between zero and one. +#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] +#[derive( + Animate, + Clone, + ComputeSquaredDistance, + Copy, + Debug, + Hash, + MallocSizeOf, + PartialEq, + PartialOrd, + SpecifiedValueInfo, + ToAnimatedZero, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +#[repr(transparent)] +pub struct ZeroToOne(pub T); + /// A clip rect for clip and image-region #[allow(missing_docs)] #[derive( diff --git a/components/style/values/specified/effects.rs b/components/style/values/specified/effects.rs index 25ef99a362e..850bb36a4a1 100644 --- a/components/style/values/specified/effects.rs +++ b/components/style/values/specified/effects.rs @@ -7,6 +7,7 @@ use crate::parser::{Parse, ParserContext}; use crate::values::computed::effects::BoxShadow as ComputedBoxShadow; use crate::values::computed::effects::SimpleShadow as ComputedSimpleShadow; +use crate::values::computed::ZeroToOneNumber as ComputedZeroToOneNumber; use crate::values::computed::NonNegativeNumber as ComputedNonNegativeNumber; use crate::values::computed::{Context, ToComputedValue}; use crate::values::generics::effects::BoxShadow as GenericBoxShadow; @@ -31,73 +32,85 @@ pub type BoxShadow = /// A specified value for a single `filter`. #[cfg(feature = "gecko")] pub type SpecifiedFilter = - GenericFilter; + GenericFilter; /// A specified value for a single `filter`. #[cfg(feature = "servo")] -pub type SpecifiedFilter = GenericFilter; +pub type SpecifiedFilter = + GenericFilter; pub use self::SpecifiedFilter as Filter; /// A value for the `` parts in `Filter`. #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] -pub struct Factor(NumberOrPercentage); +pub struct NonNegativeFactor(NumberOrPercentage); -impl Factor { - /// Parse this factor but clamp to one if the value is over 100%. - #[inline] - pub fn parse_with_clamping_to_one<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - Factor::parse(context, input).map(|v| v.clamp_to_one()) - } +/// A value for the `` parts in `Filter` which clamps to one. +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] +pub struct ZeroToOneFactor(NumberOrPercentage); - /// Clamp the value to 1 if the value is over 100%. - #[inline] - fn clamp_to_one(self) -> Self { - match self.0 { - NumberOrPercentage::Percentage(percent) => { - Factor(NumberOrPercentage::Percentage(percent.clamp_to_hundred())) - }, - NumberOrPercentage::Number(number) => { - Factor(NumberOrPercentage::Number(number.clamp_to_one())) - }, - } - } - - fn one() -> Self { - Factor(NumberOrPercentage::Number(Number::new(1.0))) +/// Clamp the value to 1 if the value is over 100%. +#[inline] +fn clamp_to_one(number: NumberOrPercentage) -> NumberOrPercentage { + match number { + NumberOrPercentage::Percentage(percent) => { + NumberOrPercentage::Percentage(percent.clamp_to_hundred()) + }, + NumberOrPercentage::Number(number) => NumberOrPercentage::Number(number.clamp_to_one()), } } -impl Parse for Factor { +macro_rules! factor_impl_common { + ($ty:ty, $computed_ty:ty) => { + impl $ty { + fn one() -> Self { + Self(NumberOrPercentage::Number(Number::new(1.))) + } + } + + impl ToComputedValue for $ty { + type ComputedValue = $computed_ty; + + #[inline] + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + use crate::values::computed::NumberOrPercentage; + match self.0.to_computed_value(context) { + NumberOrPercentage::Number(n) => n.into(), + NumberOrPercentage::Percentage(p) => p.0.into(), + } + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + Self(NumberOrPercentage::Number( + ToComputedValue::from_computed_value(&computed.0), + )) + } + } + }; +} +factor_impl_common!(NonNegativeFactor, ComputedNonNegativeNumber); +factor_impl_common!(ZeroToOneFactor, ComputedZeroToOneNumber); + +impl Parse for NonNegativeFactor { #[inline] fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { - NumberOrPercentage::parse_non_negative(context, input).map(Factor) + NumberOrPercentage::parse_non_negative(context, input).map(Self) } } -impl ToComputedValue for Factor { - type ComputedValue = ComputedNonNegativeNumber; - +impl Parse for ZeroToOneFactor { #[inline] - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - use crate::values::computed::NumberOrPercentage; - match self.0.to_computed_value(context) { - NumberOrPercentage::Number(n) => n.into(), - NumberOrPercentage::Percentage(p) => p.0.into(), - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - Factor(NumberOrPercentage::Number( - ToComputedValue::from_computed_value(&computed.0), - )) + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + NumberOrPercentage::parse_non_negative(context, input) + .map(clamp_to_one) + .map(Self) } } @@ -221,19 +234,19 @@ impl Parse for Filter { .unwrap_or(Zero::zero()), )), "brightness" => Ok(GenericFilter::Brightness( - i.try(|i| Factor::parse(context, i)) - .unwrap_or(Factor::one()), + i.try(|i| NonNegativeFactor::parse(context, i)) + .unwrap_or(NonNegativeFactor::one()), )), "contrast" => Ok(GenericFilter::Contrast( - i.try(|i| Factor::parse(context, i)) - .unwrap_or(Factor::one()), + i.try(|i| NonNegativeFactor::parse(context, i)) + .unwrap_or(NonNegativeFactor::one()), )), "grayscale" => { // Values of amount over 100% are allowed but UAs must clamp the values to 1. // https://drafts.fxtf.org/filter-effects/#funcdef-filter-grayscale Ok(GenericFilter::Grayscale( - i.try(|i| Factor::parse_with_clamping_to_one(context, i)) - .unwrap_or(Factor::one()), + i.try(|i| ZeroToOneFactor::parse(context, i)) + .unwrap_or(ZeroToOneFactor::one()), )) }, "hue-rotate" => { @@ -248,28 +261,28 @@ impl Parse for Filter { // Values of amount over 100% are allowed but UAs must clamp the values to 1. // https://drafts.fxtf.org/filter-effects/#funcdef-filter-invert Ok(GenericFilter::Invert( - i.try(|i| Factor::parse_with_clamping_to_one(context, i)) - .unwrap_or(Factor::one()), + i.try(|i| ZeroToOneFactor::parse(context, i)) + .unwrap_or(ZeroToOneFactor::one()), )) }, "opacity" => { // Values of amount over 100% are allowed but UAs must clamp the values to 1. // https://drafts.fxtf.org/filter-effects/#funcdef-filter-opacity Ok(GenericFilter::Opacity( - i.try(|i| Factor::parse_with_clamping_to_one(context, i)) - .unwrap_or(Factor::one()), + i.try(|i| ZeroToOneFactor::parse(context, i)) + .unwrap_or(ZeroToOneFactor::one()), )) }, "saturate" => Ok(GenericFilter::Saturate( - i.try(|i| Factor::parse(context, i)) - .unwrap_or(Factor::one()), + i.try(|i| NonNegativeFactor::parse(context, i)) + .unwrap_or(NonNegativeFactor::one()), )), "sepia" => { // Values of amount over 100% are allowed but UAs must clamp the values to 1. // https://drafts.fxtf.org/filter-effects/#funcdef-filter-sepia Ok(GenericFilter::Sepia( - i.try(|i| Factor::parse_with_clamping_to_one(context, i)) - .unwrap_or(Factor::one()), + i.try(|i| ZeroToOneFactor::parse(context, i)) + .unwrap_or(ZeroToOneFactor::one()), )) }, "drop-shadow" => Ok(GenericFilter::DropShadow(Parse::parse(context, i)?)),