style: Add computed value ZeroToOneNumber.

Correctly handle clamping to 1 behavior of grayscale(),
invert(), opacity() and sepia().

Differential Revision: https://phabricator.services.mozilla.com/D35509
This commit is contained in:
violet 2019-06-23 23:01:47 +00:00 committed by Emilio Cobos Álvarez
parent 9939c1ee07
commit 2fba62aba9
No known key found for this signature in database
GPG key ID: E1152D0994E4BF8A
6 changed files with 132 additions and 73 deletions

View file

@ -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<Angle, Factor, NonNegativeLength, SimpleShadow, SpecifiedUrl>;
GenericFilter<Angle, NonNegativeFactor, ZeroToOneFactor, NonNegativeLength, SimpleShadow, SpecifiedUrl>;
/// A specified value for a single `filter`.
#[cfg(feature = "servo")]
pub type SpecifiedFilter = GenericFilter<Angle, Factor, NonNegativeLength, Impossible, Impossible>;
pub type SpecifiedFilter =
GenericFilter<Angle, NonNegativeFactor, ZeroToOneFactor, NonNegativeLength, Impossible, Impossible>;
pub use self::SpecifiedFilter as Filter;
/// A value for the `<factor>` 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<Self, ParseError<'i>> {
Factor::parse(context, input).map(|v| v.clamp_to_one())
}
/// A value for the `<factor>` 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<Self, ParseError<'i>> {
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<Self, ParseError<'i>> {
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)?)),