mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
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:
parent
9939c1ee07
commit
2fba62aba9
6 changed files with 132 additions and 73 deletions
|
@ -19,8 +19,8 @@ pub type AnimatedSimpleShadow = GenericSimpleShadow<Color, Length, Length>;
|
|||
|
||||
/// An animated value for a single `filter`.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub type AnimatedFilter = GenericFilter<Angle, Number, Length, AnimatedSimpleShadow, ComputedUrl>;
|
||||
pub type AnimatedFilter = GenericFilter<Angle, Number, Number, Length, AnimatedSimpleShadow, ComputedUrl>;
|
||||
|
||||
/// An animated value for a single `filter`.
|
||||
#[cfg(not(feature = "gecko"))]
|
||||
pub type AnimatedFilter = GenericFilter<Angle, Number, Length, Impossible, Impossible>;
|
||||
pub type AnimatedFilter = GenericFilter<Angle, Number, Number, Length, Impossible, Impossible>;
|
||||
|
|
|
@ -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<Color, Length, NonNegativeLength, Length>;
|
|||
/// A computed value for a single `filter`.
|
||||
#[cfg(feature = "gecko")]
|
||||
pub type Filter =
|
||||
GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, SimpleShadow, ComputedUrl>;
|
||||
GenericFilter<Angle, NonNegativeNumber, ZeroToOneNumber, NonNegativeLength, SimpleShadow, ComputedUrl>;
|
||||
|
||||
/// A computed value for a single `filter`.
|
||||
#[cfg(feature = "servo")]
|
||||
pub type Filter =
|
||||
GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, Impossible, Impossible>;
|
||||
GenericFilter<Angle, NonNegativeNumber, ZeroToOneNumber, NonNegativeLength, Impossible, Impossible>;
|
||||
|
||||
/// A computed value for the `drop-shadow()` filter.
|
||||
pub type SimpleShadow = GenericSimpleShadow<Color, Length, NonNegativeLength>;
|
||||
|
|
|
@ -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<NonNegativeNumber> for CSSFloat {
|
|||
}
|
||||
}
|
||||
|
||||
/// A wrapper of Number, but the value between 0 and 1
|
||||
pub type ZeroToOneNumber = ZeroToOne<CSSFloat>;
|
||||
|
||||
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<CSSFloat> for ZeroToOneNumber {
|
||||
#[inline]
|
||||
fn from(number: CSSFloat) -> Self {
|
||||
Self(number)
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper of Number, but the value >= 1.
|
||||
pub type GreaterThanOrEqualToOneNumber = GreaterThanOrEqualToOne<CSSFloat>;
|
||||
|
||||
|
|
|
@ -52,34 +52,34 @@ pub use self::GenericBoxShadow as BoxShadow;
|
|||
ToShmem,
|
||||
)]
|
||||
#[repr(C, u8)]
|
||||
pub enum GenericFilter<Angle, Factor, Length, Shadow, U> {
|
||||
pub enum GenericFilter<Angle, NonNegativeFactor, ZeroToOneFactor, Length, Shadow, U> {
|
||||
/// `blur(<length>)`
|
||||
#[css(function)]
|
||||
Blur(Length),
|
||||
/// `brightness(<factor>)`
|
||||
#[css(function)]
|
||||
Brightness(Factor),
|
||||
Brightness(NonNegativeFactor),
|
||||
/// `contrast(<factor>)`
|
||||
#[css(function)]
|
||||
Contrast(Factor),
|
||||
Contrast(NonNegativeFactor),
|
||||
/// `grayscale(<factor>)`
|
||||
#[css(function)]
|
||||
Grayscale(Factor),
|
||||
Grayscale(ZeroToOneFactor),
|
||||
/// `hue-rotate(<angle>)`
|
||||
#[css(function)]
|
||||
HueRotate(Angle),
|
||||
/// `invert(<factor>)`
|
||||
#[css(function)]
|
||||
Invert(Factor),
|
||||
Invert(ZeroToOneFactor),
|
||||
/// `opacity(<factor>)`
|
||||
#[css(function)]
|
||||
Opacity(Factor),
|
||||
Opacity(ZeroToOneFactor),
|
||||
/// `saturate(<factor>)`
|
||||
#[css(function)]
|
||||
Saturate(Factor),
|
||||
Saturate(NonNegativeFactor),
|
||||
/// `sepia(<factor>)`
|
||||
#[css(function)]
|
||||
Sepia(Factor),
|
||||
Sepia(ZeroToOneFactor),
|
||||
/// `drop-shadow(...)`
|
||||
#[css(function)]
|
||||
DropShadow(Shadow),
|
||||
|
|
|
@ -227,6 +227,28 @@ impl<T: Zero> Zero for NonNegative<T> {
|
|||
)]
|
||||
pub struct GreaterThanOrEqualToOne<T>(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<T>(pub T);
|
||||
|
||||
/// A clip rect for clip and image-region
|
||||
#[allow(missing_docs)]
|
||||
#[derive(
|
||||
|
|
|
@ -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,58 +32,44 @@ 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 {
|
||||
fn clamp_to_one(number: NumberOrPercentage) -> NumberOrPercentage {
|
||||
match number {
|
||||
NumberOrPercentage::Percentage(percent) => {
|
||||
Factor(NumberOrPercentage::Percentage(percent.clamp_to_hundred()))
|
||||
},
|
||||
NumberOrPercentage::Number(number) => {
|
||||
Factor(NumberOrPercentage::Number(number.clamp_to_one()))
|
||||
NumberOrPercentage::Percentage(percent.clamp_to_hundred())
|
||||
},
|
||||
NumberOrPercentage::Number(number) => NumberOrPercentage::Number(number.clamp_to_one()),
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! factor_impl_common {
|
||||
($ty:ty, $computed_ty:ty) => {
|
||||
impl $ty {
|
||||
fn one() -> Self {
|
||||
Factor(NumberOrPercentage::Number(Number::new(1.0)))
|
||||
Self(NumberOrPercentage::Number(Number::new(1.)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Factor {
|
||||
#[inline]
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
NumberOrPercentage::parse_non_negative(context, input).map(Factor)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToComputedValue for Factor {
|
||||
type ComputedValue = ComputedNonNegativeNumber;
|
||||
impl ToComputedValue for $ty {
|
||||
type ComputedValue = $computed_ty;
|
||||
|
||||
#[inline]
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
|
@ -95,11 +82,37 @@ impl ToComputedValue for Factor {
|
|||
|
||||
#[inline]
|
||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||
Factor(NumberOrPercentage::Number(
|
||||
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(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for ZeroToOneFactor {
|
||||
#[inline]
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/// A specified value for the `drop-shadow()` filter.
|
||||
pub type SimpleShadow = GenericSimpleShadow<Option<Color>, Length, Option<NonNegativeLength>>;
|
||||
|
@ -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)?)),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue