mirror of
https://github.com/servo/servo.git
synced 2025-08-08 15:05:35 +01:00
style: Update color-mix() syntax to match the current spec
Test expectation updates for this in the latest patch of the bug. Differential Revision: https://phabricator.services.mozilla.com/D147002
This commit is contained in:
parent
3723a7b18d
commit
f4ede10441
4 changed files with 141 additions and 85 deletions
|
@ -7,7 +7,7 @@
|
||||||
use crate::values::animated::{Animate, Procedure, ToAnimatedZero};
|
use crate::values::animated::{Animate, Procedure, ToAnimatedZero};
|
||||||
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
|
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
|
||||||
use crate::values::generics::color::{Color as GenericColor, ComplexColorRatios};
|
use crate::values::generics::color::{Color as GenericColor, ComplexColorRatios};
|
||||||
use crate::values::specified::color::{ColorSpaceKind, HueAdjuster};
|
use crate::values::specified::color::{ColorInterpolationMethod, ColorSpace, HueInterpolationMethod};
|
||||||
use euclid::default::{Transform3D, Vector3D};
|
use euclid::default::{Transform3D, Vector3D};
|
||||||
|
|
||||||
/// An animated RGBA color.
|
/// An animated RGBA color.
|
||||||
|
@ -128,41 +128,40 @@ impl Color {
|
||||||
|
|
||||||
/// Mix two colors into one.
|
/// Mix two colors into one.
|
||||||
pub fn mix(
|
pub fn mix(
|
||||||
color_space: ColorSpaceKind,
|
interpolation: &ColorInterpolationMethod,
|
||||||
left_color: &Color,
|
left_color: &Color,
|
||||||
left_weight: f32,
|
left_weight: f32,
|
||||||
right_color: &Color,
|
right_color: &Color,
|
||||||
right_weight: f32,
|
right_weight: f32,
|
||||||
hue_adjuster: HueAdjuster,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
match color_space {
|
match interpolation.space {
|
||||||
ColorSpaceKind::Srgb => Self::mix_in::<RGBA>(
|
ColorSpace::Srgb => Self::mix_in::<RGBA>(
|
||||||
left_color,
|
left_color,
|
||||||
left_weight,
|
left_weight,
|
||||||
right_color,
|
right_color,
|
||||||
right_weight,
|
right_weight,
|
||||||
hue_adjuster,
|
interpolation.hue,
|
||||||
),
|
),
|
||||||
ColorSpaceKind::Xyz => Self::mix_in::<XYZA>(
|
ColorSpace::Xyz => Self::mix_in::<XYZA>(
|
||||||
left_color,
|
left_color,
|
||||||
left_weight,
|
left_weight,
|
||||||
right_color,
|
right_color,
|
||||||
right_weight,
|
right_weight,
|
||||||
hue_adjuster,
|
interpolation.hue,
|
||||||
),
|
),
|
||||||
ColorSpaceKind::Lab => Self::mix_in::<LABA>(
|
ColorSpace::Lab => Self::mix_in::<LABA>(
|
||||||
left_color,
|
left_color,
|
||||||
left_weight,
|
left_weight,
|
||||||
right_color,
|
right_color,
|
||||||
right_weight,
|
right_weight,
|
||||||
hue_adjuster,
|
interpolation.hue,
|
||||||
),
|
),
|
||||||
ColorSpaceKind::Lch => Self::mix_in::<LCHA>(
|
ColorSpace::Lch => Self::mix_in::<LCHA>(
|
||||||
left_color,
|
left_color,
|
||||||
left_weight,
|
left_weight,
|
||||||
right_color,
|
right_color,
|
||||||
right_weight,
|
right_weight,
|
||||||
hue_adjuster,
|
interpolation.hue,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +171,7 @@ impl Color {
|
||||||
left_weight: f32,
|
left_weight: f32,
|
||||||
right_color: &Color,
|
right_color: &Color,
|
||||||
right_weight: f32,
|
right_weight: f32,
|
||||||
hue_adjuster: HueAdjuster,
|
hue_interpolation: HueInterpolationMethod,
|
||||||
) -> Self
|
) -> Self
|
||||||
where
|
where
|
||||||
S: ModelledColor,
|
S: ModelledColor,
|
||||||
|
@ -180,7 +179,7 @@ impl Color {
|
||||||
let left_bg = S::from(left_color.scaled_rgba());
|
let left_bg = S::from(left_color.scaled_rgba());
|
||||||
let right_bg = S::from(right_color.scaled_rgba());
|
let right_bg = S::from(right_color.scaled_rgba());
|
||||||
|
|
||||||
let color = S::lerp(left_bg, left_weight, right_bg, right_weight, hue_adjuster);
|
let color = S::lerp(left_bg, left_weight, right_bg, right_weight, hue_interpolation);
|
||||||
let rgba: RGBA = color.into();
|
let rgba: RGBA = color.into();
|
||||||
let rgba = if !rgba.in_gamut() {
|
let rgba = if !rgba.in_gamut() {
|
||||||
// TODO: Better gamut mapping.
|
// TODO: Better gamut mapping.
|
||||||
|
@ -365,14 +364,14 @@ impl ToAnimatedZero for Color {
|
||||||
trait ModelledColor: Clone + Copy + From<RGBA> + Into<RGBA> {
|
trait ModelledColor: Clone + Copy + From<RGBA> + Into<RGBA> {
|
||||||
/// Linearly interpolate between the left and right colors.
|
/// Linearly interpolate between the left and right colors.
|
||||||
///
|
///
|
||||||
/// The HueAdjuster parameter is only for color spaces where the hue is
|
/// The HueInterpolationMethod parameter is only for color spaces where the hue is
|
||||||
/// represented as an angle (e.g., CIE LCH).
|
/// represented as an angle (e.g., CIE LCH).
|
||||||
fn lerp(
|
fn lerp(
|
||||||
left_bg: Self,
|
left_bg: Self,
|
||||||
left_weight: f32,
|
left_weight: f32,
|
||||||
right_bg: Self,
|
right_bg: Self,
|
||||||
right_weight: f32,
|
right_weight: f32,
|
||||||
hue_adjuster: HueAdjuster,
|
hue_interpolation: HueInterpolationMethod,
|
||||||
) -> Self;
|
) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +381,7 @@ impl ModelledColor for RGBA {
|
||||||
left_weight: f32,
|
left_weight: f32,
|
||||||
right_bg: Self,
|
right_bg: Self,
|
||||||
right_weight: f32,
|
right_weight: f32,
|
||||||
_: HueAdjuster,
|
_: HueInterpolationMethod,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Interpolation with alpha, as per
|
// Interpolation with alpha, as per
|
||||||
// https://drafts.csswg.org/css-color/#interpolation-alpha.
|
// https://drafts.csswg.org/css-color/#interpolation-alpha.
|
||||||
|
@ -440,7 +439,7 @@ impl ModelledColor for XYZA {
|
||||||
left_weight: f32,
|
left_weight: f32,
|
||||||
right_bg: Self,
|
right_bg: Self,
|
||||||
right_weight: f32,
|
right_weight: f32,
|
||||||
_: HueAdjuster,
|
_: HueInterpolationMethod,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Interpolation with alpha, as per
|
// Interpolation with alpha, as per
|
||||||
// https://drafts.csswg.org/css-color/#interpolation-alpha.
|
// https://drafts.csswg.org/css-color/#interpolation-alpha.
|
||||||
|
@ -503,7 +502,7 @@ impl ModelledColor for LABA {
|
||||||
left_weight: f32,
|
left_weight: f32,
|
||||||
right_bg: Self,
|
right_bg: Self,
|
||||||
right_weight: f32,
|
right_weight: f32,
|
||||||
_: HueAdjuster,
|
_: HueInterpolationMethod,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Interpolation with alpha, as per
|
// Interpolation with alpha, as per
|
||||||
// https://drafts.csswg.org/css-color/#interpolation-alpha.
|
// https://drafts.csswg.org/css-color/#interpolation-alpha.
|
||||||
|
@ -561,7 +560,7 @@ impl LCHA {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LCHA {
|
impl LCHA {
|
||||||
fn adjust(left_bg: Self, right_bg: Self, hue_adjuster: HueAdjuster) -> (Self, Self) {
|
fn adjust(left_bg: Self, right_bg: Self, hue_interpolation: HueInterpolationMethod) -> (Self, Self) {
|
||||||
use std::f32::consts::{PI, TAU};
|
use std::f32::consts::{PI, TAU};
|
||||||
|
|
||||||
let mut left_bg = left_bg;
|
let mut left_bg = left_bg;
|
||||||
|
@ -583,7 +582,7 @@ impl LCHA {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if hue_adjuster != HueAdjuster::Specified {
|
if hue_interpolation != HueInterpolationMethod::Specified {
|
||||||
// Normalize hue into [0, 2 * PI)
|
// Normalize hue into [0, 2 * PI)
|
||||||
while left_bg.hue < 0. {
|
while left_bg.hue < 0. {
|
||||||
left_bg.hue += TAU;
|
left_bg.hue += TAU;
|
||||||
|
@ -600,8 +599,8 @@ impl LCHA {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match hue_adjuster {
|
match hue_interpolation {
|
||||||
HueAdjuster::Shorter => {
|
HueInterpolationMethod::Shorter => {
|
||||||
let delta = right_bg.hue - left_bg.hue;
|
let delta = right_bg.hue - left_bg.hue;
|
||||||
|
|
||||||
if delta > PI {
|
if delta > PI {
|
||||||
|
@ -611,7 +610,7 @@ impl LCHA {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
HueAdjuster::Longer => {
|
HueInterpolationMethod::Longer => {
|
||||||
let delta = right_bg.hue - left_bg.hue;
|
let delta = right_bg.hue - left_bg.hue;
|
||||||
if 0. < delta && delta < PI {
|
if 0. < delta && delta < PI {
|
||||||
left_bg.hue += TAU;
|
left_bg.hue += TAU;
|
||||||
|
@ -620,13 +619,13 @@ impl LCHA {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
HueAdjuster::Increasing => {
|
HueInterpolationMethod::Increasing => {
|
||||||
if right_bg.hue < left_bg.hue {
|
if right_bg.hue < left_bg.hue {
|
||||||
right_bg.hue += TAU;
|
right_bg.hue += TAU;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
HueAdjuster::Decreasing => {
|
HueInterpolationMethod::Decreasing => {
|
||||||
if left_bg.hue < right_bg.hue {
|
if left_bg.hue < right_bg.hue {
|
||||||
left_bg.hue += TAU;
|
left_bg.hue += TAU;
|
||||||
}
|
}
|
||||||
|
@ -634,7 +633,7 @@ impl LCHA {
|
||||||
|
|
||||||
//Angles are not adjusted. They are interpolated like any other
|
//Angles are not adjusted. They are interpolated like any other
|
||||||
//component.
|
//component.
|
||||||
HueAdjuster::Specified => {},
|
HueInterpolationMethod::Specified => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
(left_bg, right_bg)
|
(left_bg, right_bg)
|
||||||
|
@ -647,11 +646,11 @@ impl ModelledColor for LCHA {
|
||||||
left_weight: f32,
|
left_weight: f32,
|
||||||
right_bg: Self,
|
right_bg: Self,
|
||||||
right_weight: f32,
|
right_weight: f32,
|
||||||
hue_adjuster: HueAdjuster,
|
hue_interpolation: HueInterpolationMethod,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Interpolation with alpha, as per
|
// Interpolation with alpha, as per
|
||||||
// https://drafts.csswg.org/css-color/#interpolation-alpha.
|
// https://drafts.csswg.org/css-color/#interpolation-alpha.
|
||||||
let (left_bg, right_bg) = Self::adjust(left_bg, right_bg, hue_adjuster);
|
let (left_bg, right_bg) = Self::adjust(left_bg, right_bg, hue_interpolation);
|
||||||
|
|
||||||
let mut lightness = 0.;
|
let mut lightness = 0.;
|
||||||
let mut chroma = 0.;
|
let mut chroma = 0.;
|
||||||
|
|
|
@ -21,9 +21,9 @@ use style_traits::{SpecifiedValueInfo, ToCss, ValueParseErrorKind};
|
||||||
|
|
||||||
/// A color space as defined in [1].
|
/// A color space as defined in [1].
|
||||||
///
|
///
|
||||||
/// [1]: https://drafts.csswg.org/css-color-5/#typedef-colorspace
|
/// [1]: https://drafts.csswg.org/css-color-4/#typedef-color-space
|
||||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)]
|
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)]
|
||||||
pub enum ColorSpaceKind {
|
pub enum ColorSpace {
|
||||||
/// The sRGB color space.
|
/// The sRGB color space.
|
||||||
Srgb,
|
Srgb,
|
||||||
/// The CIEXYZ color space.
|
/// The CIEXYZ color space.
|
||||||
|
@ -34,23 +34,81 @@ pub enum ColorSpaceKind {
|
||||||
Lch,
|
Lch,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A hue adjuster as defined in [1].
|
impl ColorSpace {
|
||||||
|
/// Returns whether this is a `<polar-color-space>`.
|
||||||
|
pub fn is_polar(self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Srgb | Self::Xyz | Self::Lab => false,
|
||||||
|
Self::Lch => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A hue-interpolation-method as defined in [1].
|
||||||
///
|
///
|
||||||
/// [1]: https://drafts.csswg.org/css-color-5/#typedef-hue-adjuster
|
/// [1]: https://drafts.csswg.org/css-color-4/#typedef-hue-interpolation-method
|
||||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)]
|
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss, ToShmem)]
|
||||||
pub enum HueAdjuster {
|
pub enum HueInterpolationMethod {
|
||||||
/// The "shorter" angle adjustment.
|
/// https://drafts.csswg.org/css-color-4/#shorter
|
||||||
Shorter,
|
Shorter,
|
||||||
/// The "longer" angle adjustment.
|
/// https://drafts.csswg.org/css-color-4/#longer
|
||||||
Longer,
|
Longer,
|
||||||
/// The "increasing" angle adjustment.
|
/// https://drafts.csswg.org/css-color-4/#increasing
|
||||||
Increasing,
|
Increasing,
|
||||||
/// The "decreasing" angle adjustment.
|
/// https://drafts.csswg.org/css-color-4/#decreasing
|
||||||
Decreasing,
|
Decreasing,
|
||||||
/// The "specified" angle adjustment.
|
/// https://drafts.csswg.org/css-color-4/#specified
|
||||||
Specified,
|
Specified,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// https://drafts.csswg.org/css-color-4/#color-interpolation-method
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)]
|
||||||
|
pub struct ColorInterpolationMethod {
|
||||||
|
/// The color-space the interpolation should be done in.
|
||||||
|
pub space: ColorSpace,
|
||||||
|
/// The hue interpolation method.
|
||||||
|
pub hue: HueInterpolationMethod,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for ColorInterpolationMethod {
|
||||||
|
fn parse<'i, 't>(
|
||||||
|
_: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<Self, ParseError<'i>> {
|
||||||
|
input.expect_ident_matching("in")?;
|
||||||
|
let space = ColorSpace::parse(input)?;
|
||||||
|
// https://drafts.csswg.org/css-color-4/#hue-interpolation
|
||||||
|
// Unless otherwise specified, if no specific hue interpolation
|
||||||
|
// algorithm is selected by the host syntax, the default is shorter.
|
||||||
|
let hue = if space.is_polar() {
|
||||||
|
input.try_parse(|input| -> Result<_, ParseError<'i>> {
|
||||||
|
let hue = HueInterpolationMethod::parse(input)?;
|
||||||
|
input.expect_ident_matching("hue")?;
|
||||||
|
Ok(hue)
|
||||||
|
}).unwrap_or(HueInterpolationMethod::Shorter)
|
||||||
|
} else {
|
||||||
|
HueInterpolationMethod::Shorter
|
||||||
|
};
|
||||||
|
Ok(Self { space, hue })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for ColorInterpolationMethod {
|
||||||
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
|
where
|
||||||
|
W: Write,
|
||||||
|
{
|
||||||
|
dest.write_str("in ")?;
|
||||||
|
self.space.to_css(dest)?;
|
||||||
|
if self.hue != HueInterpolationMethod::Shorter {
|
||||||
|
dest.write_char(' ')?;
|
||||||
|
self.hue.to_css(dest)?;
|
||||||
|
dest.write_str(" hue")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A restricted version of the css `color-mix()` function, which only supports
|
/// A restricted version of the css `color-mix()` function, which only supports
|
||||||
/// percentages.
|
/// percentages.
|
||||||
///
|
///
|
||||||
|
@ -58,12 +116,11 @@ pub enum HueAdjuster {
|
||||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
|
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub struct ColorMix {
|
pub struct ColorMix {
|
||||||
pub color_space: ColorSpaceKind,
|
pub interpolation: ColorInterpolationMethod,
|
||||||
pub left: Color,
|
pub left: Color,
|
||||||
pub left_percentage: Percentage,
|
pub left_percentage: Percentage,
|
||||||
pub right: Color,
|
pub right: Color,
|
||||||
pub right_percentage: Percentage,
|
pub right_percentage: Percentage,
|
||||||
pub hue_adjuster: HueAdjuster,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -82,10 +139,6 @@ fn allow_color_mix_color_spaces() -> bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(emilio): Syntax is still a bit in-flux, since [1] doesn't seem
|
|
||||||
// particularly complete, and disagrees with the examples.
|
|
||||||
//
|
|
||||||
// [1]: https://github.com/w3c/csswg-drafts/commit/a4316446112f9e814668c2caff7f826f512f8fed
|
|
||||||
impl Parse for ColorMix {
|
impl Parse for ColorMix {
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
|
@ -98,53 +151,51 @@ impl Parse for ColorMix {
|
||||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
}
|
}
|
||||||
|
|
||||||
let color_spaces_enabled = context.chrome_rules_enabled() ||
|
|
||||||
allow_color_mix_color_spaces();
|
|
||||||
|
|
||||||
input.expect_function_matching("color-mix")?;
|
input.expect_function_matching("color-mix")?;
|
||||||
|
|
||||||
// NOTE(emilio): This implements the syntax described here for now,
|
|
||||||
// might need to get updated in the future.
|
|
||||||
//
|
|
||||||
// https://github.com/w3c/csswg-drafts/issues/6066#issuecomment-789836765
|
|
||||||
input.parse_nested_block(|input| {
|
input.parse_nested_block(|input| {
|
||||||
input.expect_ident_matching("in")?;
|
let interpolation = ColorInterpolationMethod::parse(context, input)?;
|
||||||
let color_space = if color_spaces_enabled {
|
|
||||||
ColorSpaceKind::parse(input)?
|
|
||||||
} else {
|
|
||||||
input.expect_ident_matching("srgb")?;
|
|
||||||
ColorSpaceKind::Srgb
|
|
||||||
};
|
|
||||||
input.expect_comma()?;
|
input.expect_comma()?;
|
||||||
|
|
||||||
|
let try_parse_percentage = |input: &mut Parser| -> Option<Percentage> {
|
||||||
|
input.try_parse(|input| Percentage::parse_zero_to_a_hundred(context, input)).ok()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut left_percentage = try_parse_percentage(input);
|
||||||
|
|
||||||
let left = Color::parse(context, input)?;
|
let left = Color::parse(context, input)?;
|
||||||
let left_percentage = input
|
if left_percentage.is_none() {
|
||||||
.try_parse(|input| Percentage::parse(context, input))
|
left_percentage = try_parse_percentage(input);
|
||||||
.ok();
|
}
|
||||||
|
|
||||||
input.expect_comma()?;
|
input.expect_comma()?;
|
||||||
|
|
||||||
|
let mut right_percentage = try_parse_percentage(input);
|
||||||
|
|
||||||
let right = Color::parse(context, input)?;
|
let right = Color::parse(context, input)?;
|
||||||
let right_percentage = input
|
|
||||||
.try_parse(|input| Percentage::parse(context, input))
|
if right_percentage.is_none() {
|
||||||
.unwrap_or_else(|_| {
|
right_percentage = try_parse_percentage(input);
|
||||||
Percentage::new(1.0 - left_percentage.map_or(0.5, |p| p.get()))
|
}
|
||||||
});
|
|
||||||
|
let right_percentage = right_percentage.unwrap_or_else(|| {
|
||||||
|
Percentage::new(1.0 - left_percentage.map_or(0.5, |p| p.get()))
|
||||||
|
});
|
||||||
|
|
||||||
let left_percentage =
|
let left_percentage =
|
||||||
left_percentage.unwrap_or_else(|| Percentage::new(1.0 - right_percentage.get()));
|
left_percentage.unwrap_or_else(|| Percentage::new(1.0 - right_percentage.get()));
|
||||||
|
|
||||||
let hue_adjuster = input
|
if left_percentage.get() + right_percentage.get() <= 0.0 {
|
||||||
.try_parse(|input| HueAdjuster::parse(input))
|
// If the percentages sum to zero, the function is invalid.
|
||||||
.unwrap_or(HueAdjuster::Shorter);
|
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(ColorMix {
|
Ok(ColorMix {
|
||||||
color_space,
|
interpolation,
|
||||||
left,
|
left,
|
||||||
left_percentage,
|
left_percentage,
|
||||||
right,
|
right,
|
||||||
right_percentage,
|
right_percentage,
|
||||||
hue_adjuster,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -168,8 +219,8 @@ impl ToCss for ColorMix {
|
||||||
(1.0 - percent.get() - other.get()).abs() <= f32::EPSILON
|
(1.0 - percent.get() - other.get()).abs() <= f32::EPSILON
|
||||||
}
|
}
|
||||||
|
|
||||||
dest.write_str("color-mix(in ")?;
|
dest.write_str("color-mix(")?;
|
||||||
self.color_space.to_css(dest)?;
|
self.interpolation.to_css(dest)?;
|
||||||
dest.write_str(", ")?;
|
dest.write_str(", ")?;
|
||||||
self.left.to_css(dest)?;
|
self.left.to_css(dest)?;
|
||||||
if !can_omit(&self.left_percentage, &self.right_percentage, true) {
|
if !can_omit(&self.left_percentage, &self.right_percentage, true) {
|
||||||
|
@ -182,12 +233,6 @@ impl ToCss for ColorMix {
|
||||||
dest.write_str(" ")?;
|
dest.write_str(" ")?;
|
||||||
self.right_percentage.to_css(dest)?;
|
self.right_percentage.to_css(dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.hue_adjuster != HueAdjuster::Shorter {
|
|
||||||
dest.write_str(" ")?;
|
|
||||||
self.hue_adjuster.to_css(dest)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
dest.write_str(")")
|
dest.write_str(")")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -754,12 +799,11 @@ impl Color {
|
||||||
let left = mix.left.to_computed_color(context)?.to_animated_value();
|
let left = mix.left.to_computed_color(context)?.to_animated_value();
|
||||||
let right = mix.right.to_computed_color(context)?.to_animated_value();
|
let right = mix.right.to_computed_color(context)?.to_animated_value();
|
||||||
ToAnimatedValue::from_animated_value(AnimatedColor::mix(
|
ToAnimatedValue::from_animated_value(AnimatedColor::mix(
|
||||||
mix.color_space,
|
&mix.interpolation,
|
||||||
&left,
|
&left,
|
||||||
mix.left_percentage.get(),
|
mix.left_percentage.get(),
|
||||||
&right,
|
&right,
|
||||||
mix.right_percentage.get(),
|
mix.right_percentage.get(),
|
||||||
mix.hue_adjuster,
|
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
|
|
|
@ -138,6 +138,15 @@ impl Percentage {
|
||||||
Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative)
|
Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a percentage token, but rejects it if it's negative or more than
|
||||||
|
/// 100%.
|
||||||
|
pub fn parse_zero_to_a_hundred<'i, 't>(
|
||||||
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<Self, ParseError<'i>> {
|
||||||
|
Self::parse_with_clamping_mode(context, input, AllowedNumericType::ZeroToOne)
|
||||||
|
}
|
||||||
|
|
||||||
/// Clamp to 100% if the value is over 100%.
|
/// Clamp to 100% if the value is over 100%.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn clamp_to_hundred(self) -> Self {
|
pub fn clamp_to_hundred(self) -> Self {
|
||||||
|
|
|
@ -587,6 +587,8 @@ pub mod specified {
|
||||||
NonNegative,
|
NonNegative,
|
||||||
/// Allow only numeric values greater or equal to 1.0.
|
/// Allow only numeric values greater or equal to 1.0.
|
||||||
AtLeastOne,
|
AtLeastOne,
|
||||||
|
/// Allow only numeric values from 0 to 1.0.
|
||||||
|
ZeroToOne,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for AllowedNumericType {
|
impl Default for AllowedNumericType {
|
||||||
|
@ -607,6 +609,7 @@ pub mod specified {
|
||||||
AllowedNumericType::All => true,
|
AllowedNumericType::All => true,
|
||||||
AllowedNumericType::NonNegative => val >= 0.0,
|
AllowedNumericType::NonNegative => val >= 0.0,
|
||||||
AllowedNumericType::AtLeastOne => val >= 1.0,
|
AllowedNumericType::AtLeastOne => val >= 1.0,
|
||||||
|
AllowedNumericType::ZeroToOne => val >= 0.0 && val <= 1.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,9 +617,10 @@ pub mod specified {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn clamp(&self, val: f32) -> f32 {
|
pub fn clamp(&self, val: f32) -> f32 {
|
||||||
match *self {
|
match *self {
|
||||||
AllowedNumericType::NonNegative if val < 0. => 0.,
|
AllowedNumericType::All => val,
|
||||||
AllowedNumericType::AtLeastOne if val < 1. => 1.,
|
AllowedNumericType::NonNegative => val.max(0.),
|
||||||
_ => val,
|
AllowedNumericType::AtLeastOne => val.max(1.),
|
||||||
|
AllowedNumericType::ZeroToOne => val.max(0.).min(1.),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue