summaryrefslogtreecommitdiffstats
path: root/servo/components/style/values
diff options
context:
space:
mode:
Diffstat (limited to 'servo/components/style/values')
-rw-r--r--servo/components/style/values/computed/animation.rs4
-rw-r--r--servo/components/style/values/computed/color.rs5
-rw-r--r--servo/components/style/values/computed/length_percentage.rs13
-rw-r--r--servo/components/style/values/computed/mod.rs2
-rw-r--r--servo/components/style/values/specified/animation.rs38
-rw-r--r--servo/components/style/values/specified/calc.rs57
-rw-r--r--servo/components/style/values/specified/color.rs335
-rw-r--r--servo/components/style/values/specified/font.rs14
-rw-r--r--servo/components/style/values/specified/mod.rs2
9 files changed, 346 insertions, 124 deletions
diff --git a/servo/components/style/values/computed/animation.rs b/servo/components/style/values/computed/animation.rs
index 626dbe5347..b626687a36 100644
--- a/servo/components/style/values/computed/animation.rs
+++ b/servo/components/style/values/computed/animation.rs
@@ -11,8 +11,8 @@ use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
pub use crate::values::specified::animation::{
- AnimationName, ScrollAxis, ScrollTimelineName, TransitionProperty, AnimationComposition,
- AnimationDirection, AnimationFillMode, AnimationPlayState,
+ AnimationComposition, AnimationDirection, AnimationFillMode, AnimationName, AnimationPlayState,
+ ScrollAxis, ScrollTimelineName, TransitionBehavior, TransitionProperty,
};
/// A computed value for the `animation-iteration-count` property.
diff --git a/servo/components/style/values/computed/color.rs b/servo/components/style/values/computed/color.rs
index 9b5185d923..8aa50ba5ad 100644
--- a/servo/components/style/values/computed/color.rs
+++ b/servo/components/style/values/computed/color.rs
@@ -4,14 +4,13 @@
//! Computed color values.
-use crate::color::parsing::Color as CSSParserColor;
use crate::color::AbsoluteColor;
use crate::values::animated::ToAnimatedZero;
use crate::values::computed::percentage::Percentage;
use crate::values::generics::color::{
GenericCaretColor, GenericColor, GenericColorMix, GenericColorOrAuto,
};
-use std::fmt;
+use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
pub use crate::values::specified::color::{ColorScheme, ForcedColorAdjust, PrintColorAdjust};
@@ -32,7 +31,7 @@ impl ToCss for Color {
{
match *self {
Self::Absolute(ref c) => c.to_css(dest),
- Self::CurrentColor => cssparser::ToCss::to_css(&CSSParserColor::CurrentColor, dest),
+ Self::CurrentColor => dest.write_str("currentcolor"),
Self::ColorMix(ref m) => m.to_css(dest),
}
}
diff --git a/servo/components/style/values/computed/length_percentage.rs b/servo/components/style/values/computed/length_percentage.rs
index 898281a7ef..0dbd2de76d 100644
--- a/servo/components/style/values/computed/length_percentage.rs
+++ b/servo/components/style/values/computed/length_percentage.rs
@@ -443,6 +443,19 @@ impl LengthPercentage {
}
}
+ /// Converts to a `<percentage>` with given basis. Returns None if the basis is 0.
+ #[inline]
+ pub fn to_percentage_of(&self, basis: Length) -> Option<Percentage> {
+ if basis.px() == 0. {
+ return None;
+ }
+ Some(match self.unpack() {
+ Unpacked::Length(l) => Percentage(l.px() / basis.px()),
+ Unpacked::Percentage(p) => p,
+ Unpacked::Calc(ref c) => Percentage(c.resolve(basis).px() / basis.px()),
+ })
+ }
+
/// Returns the used value.
#[inline]
pub fn to_used_value(&self, containing_length: Au) -> Au {
diff --git a/servo/components/style/values/computed/mod.rs b/servo/components/style/values/computed/mod.rs
index de5db2cdab..85aadb401f 100644
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -47,7 +47,7 @@ pub use self::angle::Angle;
pub use self::animation::{
AnimationIterationCount, AnimationName, AnimationTimeline, AnimationPlayState,
AnimationFillMode, AnimationComposition, AnimationDirection, ScrollAxis,
- ScrollTimelineName, TransitionProperty, ViewTimelineInset
+ ScrollTimelineName, TransitionBehavior, TransitionProperty, ViewTimelineInset
};
pub use self::background::{BackgroundRepeat, BackgroundSize};
pub use self::basic_shape::FillRule;
diff --git a/servo/components/style/values/specified/animation.rs b/servo/components/style/values/specified/animation.rs
index e7bbf26fb3..5a1f5003f3 100644
--- a/servo/components/style/values/specified/animation.rs
+++ b/servo/components/style/values/specified/animation.rs
@@ -112,6 +112,44 @@ impl TransitionProperty {
}
}
+/// A specified value for <transition-behavior-value>.
+///
+/// https://drafts.csswg.org/css-transitions-2/#transition-behavior-property
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ MallocSizeOf,
+ Parse,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(u8)]
+pub enum TransitionBehavior {
+ /// Transitions will not be started for discrete properties, only for interpolable properties.
+ Normal,
+ /// Transitions will be started for discrete properties as well as interpolable properties.
+ AllowDiscrete,
+}
+
+impl TransitionBehavior {
+ /// Return normal, the initial value.
+ #[inline]
+ pub fn normal() -> Self {
+ Self::Normal
+ }
+
+ /// Return true if it is normal.
+ #[inline]
+ pub fn is_normal(&self) -> bool {
+ matches!(*self, Self::Normal)
+ }
+}
+
/// https://drafts.csswg.org/css-animations/#animation-iteration-count
#[derive(Copy, Clone, Debug, MallocSizeOf, PartialEq, Parse, SpecifiedValueInfo, ToCss, ToShmem)]
pub enum AnimationIterationCount {
diff --git a/servo/components/style/values/specified/calc.rs b/servo/components/style/values/specified/calc.rs
index 2660864319..17f043ac58 100644
--- a/servo/components/style/values/specified/calc.rs
+++ b/servo/components/style/values/specified/calc.rs
@@ -6,7 +6,6 @@
//!
//! [calc]: https://drafts.csswg.org/css-values/#calc-notation
-use crate::color::parsing::{AngleOrNumber, NumberOrPercentage};
use crate::parser::ParserContext;
use crate::values::generics::calc::{
self as generic, CalcNodeLeaf, CalcUnits, MinMaxOp, ModRemOp, PositivePercentageBasis,
@@ -185,7 +184,11 @@ impl generic::CalcNodeLeaf for Leaf {
let self_negative = self.is_negative();
if self_negative != other.is_negative() {
- return Some(if self_negative { cmp::Ordering::Less } else { cmp::Ordering::Greater });
+ return Some(if self_negative {
+ cmp::Ordering::Less
+ } else {
+ cmp::Ordering::Greater
+ });
}
match (self, other) {
@@ -482,7 +485,7 @@ impl CalcNode {
/// Parse a top-level `calc` expression, with all nested sub-expressions.
///
/// This is in charge of parsing, for example, `2 + 3 * 100%`.
- fn parse<'i, 't>(
+ pub fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
function: MathFunction,
@@ -524,13 +527,18 @@ impl CalcNode {
}
let value = Self::parse_argument(context, input, allowed_units)?;
- input.expect_comma()?;
- let step = Self::parse_argument(context, input, allowed_units)?;
+
+ // <step> defaults to the number 1 if not provided
+ // https://drafts.csswg.org/css-values-4/#funcdef-round
+ let step = input.try_parse(|input| {
+ input.expect_comma()?;
+ Self::parse_argument(context, input, allowed_units)
+ });
Ok(Self::Round {
strategy: strategy.unwrap_or(RoundingStrategy::Nearest),
value: Box::new(value),
- step: Box::new(step),
+ step: Box::new(step.unwrap_or(Self::Leaf(Leaf::Number(1.0)))),
})
},
MathFunction::Mod | MathFunction::Rem => {
@@ -1046,41 +1054,4 @@ impl CalcNode {
.to_resolution()
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
-
- /// Convenience parsing function for `<number>` or `<percentage>`.
- pub fn parse_number_or_percentage<'i, 't>(
- context: &ParserContext,
- input: &mut Parser<'i, 't>,
- function: MathFunction,
- ) -> Result<NumberOrPercentage, ParseError<'i>> {
- let node = Self::parse(context, input, function, CalcUnits::PERCENTAGE)?;
-
- if let Ok(value) = node.to_number() {
- return Ok(NumberOrPercentage::Number { value });
- }
-
- match node.to_percentage() {
- Ok(unit_value) => Ok(NumberOrPercentage::Percentage { unit_value }),
- Err(()) => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
- }
- }
-
- /// Convenience parsing function for `<number>` or `<angle>`.
- pub fn parse_angle_or_number<'i, 't>(
- context: &ParserContext,
- input: &mut Parser<'i, 't>,
- function: MathFunction,
- ) -> Result<AngleOrNumber, ParseError<'i>> {
- let node = Self::parse(context, input, function, CalcUnits::ANGLE)?;
-
- if let Ok(angle) = node.to_angle() {
- let degrees = angle.degrees();
- return Ok(AngleOrNumber::Angle { degrees });
- }
-
- match node.to_number() {
- Ok(value) => Ok(AngleOrNumber::Number { value }),
- Err(()) => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
- }
- }
}
diff --git a/servo/components/style/values/specified/color.rs b/servo/components/style/values/specified/color.rs
index 3a19a2f4a3..3694b4e9bc 100644
--- a/servo/components/style/values/specified/color.rs
+++ b/servo/components/style/values/specified/color.rs
@@ -5,19 +5,21 @@
//! Specified color values.
use super::AllowQuirks;
-use crate::color::parsing::{
- self, AngleOrNumber, Color as CSSParserColor, FromParsedColor, NumberOrPercentage,
-};
+use crate::color::component::ColorComponent;
+use crate::color::convert::normalize_hue;
+use crate::color::parsing::{self, FromParsedColor, NumberOrAngle, NumberOrPercentage};
use crate::color::{mix::ColorInterpolationMethod, AbsoluteColor, ColorSpace};
use crate::media_queries::Device;
use crate::parser::{Parse, ParserContext};
use crate::values::computed::{Color as ComputedColor, Context, ToComputedValue};
+use crate::values::generics::calc::CalcUnits;
use crate::values::generics::color::{
ColorMixFlags, GenericCaretColor, GenericColorMix, GenericColorOrAuto,
};
-use crate::values::specified::calc::CalcNode;
+use crate::values::specified::calc::{CalcNode, Leaf};
use crate::values::specified::Percentage;
use crate::values::{normalize, CustomIdent};
+use cssparser::color::OPAQUE;
use cssparser::{color::PredefinedColorSpace, BasicParseErrorKind, ParseErrorKind, Parser, Token};
use itoa;
use std::fmt::{self, Write};
@@ -428,94 +430,217 @@ impl SystemColor {
}
}
+impl<T> From<ColorComponent<T>> for Option<T> {
+ fn from(value: ColorComponent<T>) -> Self {
+ match value {
+ ColorComponent::None => None,
+ ColorComponent::Value(value) => Some(value),
+ }
+ }
+}
+
+impl ColorComponent<NumberOrPercentage> {
+ #[inline]
+ fn into_alpha(self) -> Option<f32> {
+ match self {
+ ColorComponent::None => None,
+ ColorComponent::Value(number_or_percentage) => {
+ Some(normalize(number_or_percentage.to_number(1.0)).clamp(0.0, OPAQUE))
+ },
+ }
+ }
+}
+
impl FromParsedColor for Color {
fn from_current_color() -> Self {
Color::CurrentColor
}
- fn from_rgba(r: u8, g: u8, b: u8, a: f32) -> Self {
- AbsoluteColor::srgb_legacy(r, g, b, a).into()
+ fn from_rgba(
+ red: ColorComponent<u8>,
+ green: ColorComponent<u8>,
+ blue: ColorComponent<u8>,
+ alpha: ColorComponent<NumberOrPercentage>,
+ ) -> Self {
+ macro_rules! c {
+ ($c:expr) => {{
+ match $c {
+ ColorComponent::None => 0u8,
+ ColorComponent::Value(value) => value,
+ }
+ }};
+ }
+
+ // Legacy rgb() doesn't support "none" alpha values and falls back to 0.
+ let alpha = alpha.into_alpha().unwrap_or(0.0);
+
+ AbsoluteColor::srgb_legacy(c!(red), c!(green), c!(blue), alpha).into()
}
fn from_hsl(
- hue: Option<f32>,
- saturation: Option<f32>,
- lightness: Option<f32>,
- alpha: Option<f32>,
+ hue: ColorComponent<NumberOrAngle>,
+ saturation: ColorComponent<NumberOrPercentage>,
+ lightness: ColorComponent<NumberOrPercentage>,
+ alpha: ColorComponent<NumberOrPercentage>,
) -> Self {
- AbsoluteColor::new(ColorSpace::Hsl, hue, saturation, lightness, alpha).into()
+ // Percent reference range for S and L: 0% = 0.0, 100% = 100.0
+ const LIGHTNESS_RANGE: f32 = 100.0;
+ const SATURATION_RANGE: f32 = 100.0;
+
+ let hue = hue.map_value(|angle| normalize_hue(angle.degrees()));
+ let saturation =
+ saturation.map_value(|s| s.to_number(SATURATION_RANGE).clamp(0.0, SATURATION_RANGE));
+ let lightness =
+ lightness.map_value(|l| l.to_number(LIGHTNESS_RANGE).clamp(0.0, LIGHTNESS_RANGE));
+
+ AbsoluteColor::new(
+ ColorSpace::Hsl,
+ hue,
+ saturation,
+ lightness,
+ alpha.into_alpha(),
+ )
+ .into()
}
fn from_hwb(
- hue: Option<f32>,
- whiteness: Option<f32>,
- blackness: Option<f32>,
- alpha: Option<f32>,
+ hue: ColorComponent<NumberOrAngle>,
+ whiteness: ColorComponent<NumberOrPercentage>,
+ blackness: ColorComponent<NumberOrPercentage>,
+ alpha: ColorComponent<NumberOrPercentage>,
) -> Self {
- AbsoluteColor::new(ColorSpace::Hwb, hue, whiteness, blackness, alpha).into()
+ // Percent reference range for W and B: 0% = 0.0, 100% = 100.0
+ const WHITENESS_RANGE: f32 = 100.0;
+ const BLACKNESS_RANGE: f32 = 100.0;
+
+ let hue = hue.map_value(|angle| normalize_hue(angle.degrees()));
+ let whiteness =
+ whiteness.map_value(|w| w.to_number(WHITENESS_RANGE).clamp(0.0, WHITENESS_RANGE));
+ let blackness =
+ blackness.map_value(|b| b.to_number(BLACKNESS_RANGE).clamp(0.0, BLACKNESS_RANGE));
+
+ AbsoluteColor::new(
+ ColorSpace::Hwb,
+ hue,
+ whiteness,
+ blackness,
+ alpha.into_alpha(),
+ )
+ .into()
}
fn from_lab(
- lightness: Option<f32>,
- a: Option<f32>,
- b: Option<f32>,
- alpha: Option<f32>,
+ lightness: ColorComponent<NumberOrPercentage>,
+ a: ColorComponent<NumberOrPercentage>,
+ b: ColorComponent<NumberOrPercentage>,
+ alpha: ColorComponent<NumberOrPercentage>,
) -> Self {
- AbsoluteColor::new(ColorSpace::Lab, lightness, a, b, alpha).into()
+ // for L: 0% = 0.0, 100% = 100.0
+ // for a and b: -100% = -125, 100% = 125
+ const LIGHTNESS_RANGE: f32 = 100.0;
+ const A_B_RANGE: f32 = 125.0;
+
+ let lightness = lightness.map_value(|l| l.to_number(LIGHTNESS_RANGE));
+ let a = a.map_value(|a| a.to_number(A_B_RANGE));
+ let b = b.map_value(|b| b.to_number(A_B_RANGE));
+
+ AbsoluteColor::new(ColorSpace::Lab, lightness, a, b, alpha.into_alpha()).into()
}
fn from_lch(
- lightness: Option<f32>,
- chroma: Option<f32>,
- hue: Option<f32>,
- alpha: Option<f32>,
+ lightness: ColorComponent<NumberOrPercentage>,
+ chroma: ColorComponent<NumberOrPercentage>,
+ hue: ColorComponent<NumberOrAngle>,
+ alpha: ColorComponent<NumberOrPercentage>,
) -> Self {
- AbsoluteColor::new(ColorSpace::Lch, lightness, chroma, hue, alpha).into()
+ // for L: 0% = 0.0, 100% = 100.0
+ // for C: 0% = 0, 100% = 150
+ const LIGHTNESS_RANGE: f32 = 100.0;
+ const CHROMA_RANGE: f32 = 150.0;
+
+ let lightness = lightness.map_value(|l| l.to_number(LIGHTNESS_RANGE));
+ let chroma = chroma.map_value(|c| c.to_number(CHROMA_RANGE));
+ let hue = hue.map_value(|angle| normalize_hue(angle.degrees()));
+
+ AbsoluteColor::new(ColorSpace::Lch, lightness, chroma, hue, alpha.into_alpha()).into()
}
fn from_oklab(
- lightness: Option<f32>,
- a: Option<f32>,
- b: Option<f32>,
- alpha: Option<f32>,
+ lightness: ColorComponent<NumberOrPercentage>,
+ a: ColorComponent<NumberOrPercentage>,
+ b: ColorComponent<NumberOrPercentage>,
+ alpha: ColorComponent<NumberOrPercentage>,
) -> Self {
- AbsoluteColor::new(ColorSpace::Oklab, lightness, a, b, alpha).into()
+ // for L: 0% = 0.0, 100% = 1.0
+ // for a and b: -100% = -0.4, 100% = 0.4
+ const LIGHTNESS_RANGE: f32 = 1.0;
+ const A_B_RANGE: f32 = 0.4;
+
+ let lightness = lightness.map_value(|l| l.to_number(LIGHTNESS_RANGE));
+ let a = a.map_value(|a| a.to_number(A_B_RANGE));
+ let b = b.map_value(|b| b.to_number(A_B_RANGE));
+
+ AbsoluteColor::new(ColorSpace::Oklab, lightness, a, b, alpha.into_alpha()).into()
}
fn from_oklch(
- lightness: Option<f32>,
- chroma: Option<f32>,
- hue: Option<f32>,
- alpha: Option<f32>,
+ lightness: ColorComponent<NumberOrPercentage>,
+ chroma: ColorComponent<NumberOrPercentage>,
+ hue: ColorComponent<NumberOrAngle>,
+ alpha: ColorComponent<NumberOrPercentage>,
) -> Self {
- AbsoluteColor::new(ColorSpace::Oklch, lightness, chroma, hue, alpha).into()
+ // for L: 0% = 0.0, 100% = 1.0
+ // for C: 0% = 0.0 100% = 0.4
+ const LIGHTNESS_RANGE: f32 = 1.0;
+ const CHROMA_RANGE: f32 = 0.4;
+
+ let lightness = lightness.map_value(|l| l.to_number(LIGHTNESS_RANGE));
+ let chroma = chroma.map_value(|c| c.to_number(CHROMA_RANGE));
+ let hue = hue.map_value(|angle| normalize_hue(angle.degrees()));
+
+ AbsoluteColor::new(
+ ColorSpace::Oklch,
+ lightness,
+ chroma,
+ hue,
+ alpha.into_alpha(),
+ )
+ .into()
}
fn from_color_function(
color_space: PredefinedColorSpace,
- c1: Option<f32>,
- c2: Option<f32>,
- c3: Option<f32>,
- alpha: Option<f32>,
+ c1: ColorComponent<NumberOrPercentage>,
+ c2: ColorComponent<NumberOrPercentage>,
+ c3: ColorComponent<NumberOrPercentage>,
+ alpha: ColorComponent<NumberOrPercentage>,
) -> Self {
- AbsoluteColor::new(color_space.into(), c1, c2, c3, alpha).into()
+ let c1 = c1.map_value(|c| c.to_number(1.0));
+ let c2 = c2.map_value(|c| c.to_number(1.0));
+ let c3 = c3.map_value(|c| c.to_number(1.0));
+
+ AbsoluteColor::new(color_space.into(), c1, c2, c3, alpha.into_alpha()).into()
}
}
struct ColorParser<'a, 'b: 'a>(&'a ParserContext<'b>);
+
impl<'a, 'b: 'a, 'i: 'a> parsing::ColorParser<'i> for ColorParser<'a, 'b> {
type Output = Color;
- type Error = StyleParseErrorKind<'i>;
- fn parse_angle_or_number<'t>(
+ fn parse_number_or_angle<'t>(
&self,
input: &mut Parser<'i, 't>,
- ) -> Result<AngleOrNumber, ParseError<'i>> {
+ allow_none: bool,
+ ) -> Result<ColorComponent<NumberOrAngle>, ParseError<'i>> {
use crate::values::specified::Angle;
let location = input.current_source_location();
let token = input.next()?.clone();
- match token {
+ Ok(match token {
+ Token::Ident(ref value) if allow_none && value.eq_ignore_ascii_case("none") => {
+ ColorComponent::None
+ },
Token::Dimension {
value, ref unit, ..
} => {
@@ -526,44 +651,125 @@ impl<'a, 'b: 'a, 'i: 'a> parsing::ColorParser<'i> for ColorParser<'a, 'b> {
Err(()) => return Err(location.new_unexpected_token_error(token.clone())),
};
- Ok(AngleOrNumber::Angle { degrees })
+ ColorComponent::Value(NumberOrAngle::Angle { degrees })
},
- Token::Number { value, .. } => Ok(AngleOrNumber::Number { value }),
+ Token::Number { value, .. } => ColorComponent::Value(NumberOrAngle::Number { value }),
Token::Function(ref name) => {
let function = CalcNode::math_function(self.0, name, location)?;
- CalcNode::parse_angle_or_number(self.0, input, function)
+ let node = CalcNode::parse(self.0, input, function, CalcUnits::ANGLE)?;
+
+ // If we can resolve the calc node, then use the value.
+ match node.resolve() {
+ Ok(Leaf::Number(value)) => {
+ ColorComponent::Value(NumberOrAngle::Number { value })
+ },
+ Ok(Leaf::Angle(angle)) => ColorComponent::Value(NumberOrAngle::Angle {
+ degrees: angle.degrees(),
+ }),
+ _ => {
+ return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+ },
+ }
},
t => return Err(location.new_unexpected_token_error(t)),
- }
+ })
}
- fn parse_percentage<'t>(&self, input: &mut Parser<'i, 't>) -> Result<f32, ParseError<'i>> {
- Ok(Percentage::parse(self.0, input)?.get())
+ fn parse_percentage<'t>(
+ &self,
+ input: &mut Parser<'i, 't>,
+ allow_none: bool,
+ ) -> Result<ColorComponent<f32>, ParseError<'i>> {
+ let location = input.current_source_location();
+
+ Ok(match *input.next()? {
+ Token::Ident(ref value) if allow_none && value.eq_ignore_ascii_case("none") => {
+ ColorComponent::None
+ },
+ Token::Percentage { unit_value, .. } => ColorComponent::Value(unit_value),
+ Token::Function(ref name) => {
+ let function = CalcNode::math_function(self.0, name, location)?;
+ let node = CalcNode::parse(self.0, input, function, CalcUnits::PERCENTAGE)?;
+
+ // If we can resolve the calc node, then use the value.
+ let Ok(resolved_leaf) = node.resolve() else {
+ return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
+ };
+ if let Leaf::Percentage(value) = resolved_leaf {
+ ColorComponent::Value(value)
+ } else {
+ return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
+ }
+ },
+ ref t => return Err(location.new_unexpected_token_error(t.clone())),
+ })
}
- fn parse_number<'t>(&self, input: &mut Parser<'i, 't>) -> Result<f32, ParseError<'i>> {
- use crate::values::specified::Number;
+ fn parse_number<'t>(
+ &self,
+ input: &mut Parser<'i, 't>,
+ allow_none: bool,
+ ) -> Result<ColorComponent<f32>, ParseError<'i>> {
+ let location = input.current_source_location();
+
+ Ok(match *input.next()? {
+ Token::Ident(ref value) if allow_none && value.eq_ignore_ascii_case("none") => {
+ ColorComponent::None
+ },
+ Token::Number { value, .. } => ColorComponent::Value(value),
+ Token::Function(ref name) => {
+ let function = CalcNode::math_function(self.0, name, location)?;
+ let node = CalcNode::parse(self.0, input, function, CalcUnits::empty())?;
- Ok(Number::parse(self.0, input)?.get())
+ // If we can resolve the calc node, then use the value.
+ let Ok(resolved_leaf) = node.resolve() else {
+ return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
+ };
+ if let Leaf::Number(value) = resolved_leaf {
+ ColorComponent::Value(value)
+ } else {
+ return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
+ }
+ },
+ ref t => return Err(location.new_unexpected_token_error(t.clone())),
+ })
}
fn parse_number_or_percentage<'t>(
&self,
input: &mut Parser<'i, 't>,
- ) -> Result<NumberOrPercentage, ParseError<'i>> {
+ allow_none: bool,
+ ) -> Result<ColorComponent<NumberOrPercentage>, ParseError<'i>> {
let location = input.current_source_location();
- match *input.next()? {
- Token::Number { value, .. } => Ok(NumberOrPercentage::Number { value }),
+ Ok(match *input.next()? {
+ Token::Ident(ref value) if allow_none && value.eq_ignore_ascii_case("none") => {
+ ColorComponent::None
+ },
+ Token::Number { value, .. } => {
+ ColorComponent::Value(NumberOrPercentage::Number { value })
+ },
Token::Percentage { unit_value, .. } => {
- Ok(NumberOrPercentage::Percentage { unit_value })
+ ColorComponent::Value(NumberOrPercentage::Percentage { unit_value })
},
Token::Function(ref name) => {
let function = CalcNode::math_function(self.0, name, location)?;
- CalcNode::parse_number_or_percentage(self.0, input, function)
+ let node = CalcNode::parse(self.0, input, function, CalcUnits::PERCENTAGE)?;
+
+ // If we can resolve the calc node, then use the value.
+ let Ok(resolved_leaf) = node.resolve() else {
+ return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
+ };
+ if let Leaf::Percentage(unit_value) = resolved_leaf {
+ ColorComponent::Value(NumberOrPercentage::Percentage { unit_value })
+ } else if let Leaf::Number(value) = resolved_leaf {
+ ColorComponent::Value(NumberOrPercentage::Number { value })
+ } else {
+ return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
+ }
},
ref t => return Err(location.new_unexpected_token_error(t.clone())),
- }
+ })
}
}
@@ -700,7 +906,7 @@ impl ToCss for Color {
W: Write,
{
match *self {
- Color::CurrentColor => cssparser::ToCss::to_css(&CSSParserColor::CurrentColor, dest),
+ Color::CurrentColor => dest.write_str("currentcolor"),
Color::Absolute(ref absolute) => absolute.to_css(dest),
Color::ColorMix(ref mix) => mix.to_css(dest),
Color::LightDark(ref ld) => ld.to_css(dest),
@@ -772,7 +978,12 @@ impl Color {
loc: &cssparser::SourceLocation,
) -> Result<Self, ParseError<'i>> {
match cssparser::color::parse_hash_color(bytes) {
- Ok((r, g, b, a)) => Ok(Self::from_rgba(r, g, b, a)),
+ Ok((r, g, b, a)) => Ok(Self::from_rgba(
+ r.into(),
+ g.into(),
+ b.into(),
+ ColorComponent::Value(NumberOrPercentage::Number { value: a }),
+ )),
Err(()) => Err(loc.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
}
}
diff --git a/servo/components/style/values/specified/font.rs b/servo/components/style/values/specified/font.rs
index 2435682ce3..db3d871a0f 100644
--- a/servo/components/style/values/specified/font.rs
+++ b/servo/components/style/values/specified/font.rs
@@ -450,16 +450,6 @@ impl ToComputedValue for FontStretch {
}
}
-#[cfg(feature = "gecko")]
-fn math_depth_enabled(_context: &ParserContext) -> bool {
- static_prefs::pref!("layout.css.math-depth.enabled")
-}
-
-#[cfg(feature = "servo")]
-fn math_depth_enabled(_context: &ParserContext) -> bool {
- false
-}
-
/// CSS font keywords
#[derive(
Animate,
@@ -496,7 +486,7 @@ pub enum FontSizeKeyword {
XXXLarge,
/// Indicate whether to apply font-size: math is specified so that extra
/// scaling due to math-depth changes is applied during the cascade.
- #[parse(condition = "math_depth_enabled")]
+ #[cfg(feature="gecko")]
Math,
#[css(skip)]
None,
@@ -1018,7 +1008,7 @@ impl FontSize {
return Ok(FontSize::Length(lp));
}
- if let Ok(kw) = input.try_parse(|i| FontSizeKeyword::parse(context, i)) {
+ if let Ok(kw) = input.try_parse(|i| FontSizeKeyword::parse(i)) {
return Ok(FontSize::Keyword(KeywordInfo::new(kw)));
}
diff --git a/servo/components/style/values/specified/mod.rs b/servo/components/style/values/specified/mod.rs
index 7fc76b3c07..1a12ca56e7 100644
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -33,7 +33,7 @@ pub use self::angle::{AllowUnitlessZeroAngle, Angle};
pub use self::animation::{
AnimationIterationCount, AnimationName, AnimationTimeline, AnimationPlayState,
AnimationFillMode, AnimationComposition, AnimationDirection, ScrollAxis,
- ScrollTimelineName, TransitionProperty, ViewTimelineInset
+ ScrollTimelineName, TransitionBehavior, TransitionProperty, ViewTimelineInset
};
pub use self::background::{BackgroundRepeat, BackgroundSize};
pub use self::basic_shape::FillRule;