From a90a5cba08fdf6c0ceb95101c275108a152a3aed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 07:35:37 +0200 Subject: Merging upstream version 127.0. Signed-off-by: Daniel Baumann --- servo/components/style/values/specified/box.rs | 24 +-- servo/components/style/values/specified/calc.rs | 82 +++++--- servo/components/style/values/specified/color.rs | 216 +-------------------- .../components/style/values/specified/counters.rs | 52 +++-- 4 files changed, 97 insertions(+), 277 deletions(-) (limited to 'servo/components/style/values/specified') diff --git a/servo/components/style/values/specified/box.rs b/servo/components/style/values/specified/box.rs index ee50227504..9b87103048 100644 --- a/servo/components/style/values/specified/box.rs +++ b/servo/components/style/values/specified/box.rs @@ -1495,6 +1495,9 @@ pub enum Appearance { /// For HTML's #[parse(condition = "ParserContext::chrome_rules_enabled")] NumberInput, + /// For HTML's + #[parse(condition = "ParserContext::chrome_rules_enabled")] + PasswordInput, /// The progress bar's progress indicator #[parse(condition = "ParserContext::chrome_rules_enabled")] Progresschunk, @@ -1576,27 +1579,6 @@ pub enum Appearance { /// A tooltip. #[parse(condition = "ParserContext::chrome_rules_enabled")] Tooltip, - /// A listbox or tree widget header - #[parse(condition = "ParserContext::chrome_rules_enabled")] - Treeheader, - /// An individual header cell - #[parse(condition = "ParserContext::chrome_rules_enabled")] - Treeheadercell, - /// A tree item. - #[parse(condition = "ParserContext::chrome_rules_enabled")] - Treeitem, - /// A tree widget branch line - #[parse(condition = "ParserContext::chrome_rules_enabled")] - Treeline, - /// A tree widget twisty. - #[parse(condition = "ParserContext::chrome_rules_enabled")] - Treetwisty, - /// Open tree widget twisty. - #[parse(condition = "ParserContext::chrome_rules_enabled")] - Treetwistyopen, - /// A tree widget. - #[parse(condition = "ParserContext::chrome_rules_enabled")] - Treeview, /// Mac help button. #[parse(condition = "ParserContext::chrome_rules_enabled")] diff --git a/servo/components/style/values/specified/calc.rs b/servo/components/style/values/specified/calc.rs index 17f043ac58..a354963ce1 100644 --- a/servo/components/style/values/specified/calc.rs +++ b/servo/components/style/values/specified/calc.rs @@ -6,6 +6,7 @@ //! //! [calc]: https://drafts.csswg.org/css-values/#calc-notation +use crate::color::parsing::ChannelKeyword; use crate::parser::ParserContext; use crate::values::generics::calc::{ self as generic, CalcNodeLeaf, CalcUnits, MinMaxOp, ModRemOp, PositivePercentageBasis, @@ -80,6 +81,8 @@ pub enum Leaf { Time(Time), /// `` Resolution(Resolution), + /// A component of a color. + ColorComponent(ChannelKeyword), /// `` Percentage(CSSFloat), /// `` @@ -107,6 +110,7 @@ impl ToCss for Leaf { Self::Percentage(p) => serialize_percentage(p, dest), Self::Angle(ref a) => a.to_css(dest), Self::Time(ref t) => t.to_css(dest), + Self::ColorComponent(ref s) => s.to_css(dest), } } } @@ -152,19 +156,21 @@ impl generic::CalcNodeLeaf for Leaf { Leaf::Angle(_) => CalcUnits::ANGLE, Leaf::Time(_) => CalcUnits::TIME, Leaf::Resolution(_) => CalcUnits::RESOLUTION, + Leaf::ColorComponent(_) => CalcUnits::COLOR_COMPONENT, Leaf::Percentage(_) => CalcUnits::PERCENTAGE, Leaf::Number(_) => CalcUnits::empty(), } } - fn unitless_value(&self) -> f32 { - match *self { + fn unitless_value(&self) -> Option { + Some(match *self { Self::Length(ref l) => l.unitless_value(), Self::Percentage(n) | Self::Number(n) => n, Self::Resolution(ref r) => r.dppx(), Self::Angle(ref a) => a.degrees(), Self::Time(ref t) => t.seconds(), - } + Self::ColorComponent(_) => return None, + }) } fn new_number(value: f32) -> Self { @@ -182,8 +188,8 @@ impl generic::CalcNodeLeaf for Leaf { return None; } - let self_negative = self.is_negative(); - if self_negative != other.is_negative() { + let self_negative = self.is_negative().unwrap_or(false); + if self_negative != other.is_negative().unwrap_or(false) { return Some(if self_negative { cmp::Ordering::Less } else { @@ -198,10 +204,11 @@ impl generic::CalcNodeLeaf for Leaf { (&Time(ref one), &Time(ref other)) => one.seconds().partial_cmp(&other.seconds()), (&Resolution(ref one), &Resolution(ref other)) => one.dppx().partial_cmp(&other.dppx()), (&Number(ref one), &Number(ref other)) => one.partial_cmp(other), + (&ColorComponent(ref one), &ColorComponent(ref other)) => one.partial_cmp(other), _ => { match *self { Length(..) | Percentage(..) | Angle(..) | Time(..) | Number(..) | - Resolution(..) => {}, + Resolution(..) | ColorComponent(..) => {}, } unsafe { debug_unreachable!("Forgot a branch?"); @@ -216,14 +223,15 @@ impl generic::CalcNodeLeaf for Leaf { Leaf::Angle(_) | Leaf::Time(_) | Leaf::Resolution(_) | - Leaf::Percentage(_) => None, + Leaf::Percentage(_) | + Leaf::ColorComponent(_) => None, Leaf::Number(value) => Some(value), } } fn sort_key(&self) -> SortKey { match *self { - Self::Number(..) => SortKey::Number, + Self::Number(..) | Self::ColorComponent(..) => SortKey::Number, Self::Percentage(..) => SortKey::Percentage, Self::Time(..) => SortKey::Sec, Self::Resolution(..) => SortKey::Dppx, @@ -316,7 +324,7 @@ impl generic::CalcNodeLeaf for Leaf { _ => { match *other { Number(..) | Percentage(..) | Angle(..) | Time(..) | Resolution(..) | - Length(..) => {}, + Length(..) | ColorComponent(..) => {}, } unsafe { debug_unreachable!(); @@ -336,15 +344,17 @@ impl generic::CalcNodeLeaf for Leaf { } else { // The right side is not a number, so the result should be in the units of the right // side. - other.map(|v| v * *left); - std::mem::swap(self, other); - true + if other.map(|v| v * *left).is_ok() { + std::mem::swap(self, other); + true + } else { + false + } } } else if let Self::Number(ref right) = *other { // The left side is not a number, but the right side is, so the result is the left // side unit. - self.map(|v| v * *right); - true + self.map(|v| v * *right).is_ok() } else { // Neither side is a number, so a product is not possible. false @@ -392,7 +402,7 @@ impl generic::CalcNodeLeaf for Leaf { _ => { match *other { Number(..) | Percentage(..) | Angle(..) | Time(..) | Length(..) | - Resolution(..) => {}, + Resolution(..) | ColorComponent(..) => {}, } unsafe { debug_unreachable!(); @@ -401,15 +411,16 @@ impl generic::CalcNodeLeaf for Leaf { } } - fn map(&mut self, mut op: impl FnMut(f32) -> f32) { - match self { + fn map(&mut self, mut op: impl FnMut(f32) -> f32) -> Result<(), ()> { + Ok(match self { Leaf::Length(one) => *one = one.map(op), Leaf::Angle(one) => *one = specified::Angle::from_calc(op(one.degrees())), Leaf::Time(one) => *one = specified::Time::from_seconds(op(one.seconds())), Leaf::Resolution(one) => *one = specified::Resolution::from_dppx(op(one.dppx())), Leaf::Percentage(one) => *one = op(*one), Leaf::Number(one) => *one = op(*one), - } + Leaf::ColorComponent(..) => return Err(()), + }) } } @@ -468,15 +479,30 @@ impl CalcNode { CalcNode::parse(context, input, function, allowed_units) }, &Token::Ident(ref ident) => { - let number = match_ignore_ascii_case! { &**ident, - "e" => std::f32::consts::E, - "pi" => std::f32::consts::PI, - "infinity" => f32::INFINITY, - "-infinity" => f32::NEG_INFINITY, - "nan" => f32::NAN, - _ => return Err(location.new_unexpected_token_error(Token::Ident(ident.clone()))), + let leaf = match_ignore_ascii_case! { &**ident, + "e" => Leaf::Number(std::f32::consts::E), + "pi" => Leaf::Number(std::f32::consts::PI), + "infinity" => Leaf::Number(f32::INFINITY), + "-infinity" => Leaf::Number(f32::NEG_INFINITY), + "nan" => Leaf::Number(f32::NAN), + _ => { + if crate::color::parsing::rcs_enabled() && + allowed_units.intersects(CalcUnits::COLOR_COMPONENT) + { + if let Ok(channel_keyword) = ChannelKeyword::from_ident(&ident) { + Leaf::ColorComponent(channel_keyword) + } else { + return Err(location + .new_unexpected_token_error(Token::Ident(ident.clone()))); + } + } else { + return Err( + location.new_unexpected_token_error(Token::Ident(ident.clone())) + ); + } + }, }; - Ok(CalcNode::Leaf(Leaf::Number(number))) + Ok(CalcNode::Leaf(leaf)) }, t => Err(location.new_unexpected_token_error(t.clone())), } @@ -817,7 +843,9 @@ impl CalcNode { if let Ok(resolved) = right.resolve() { if let Some(number) = resolved.as_number() { if number != 1.0 && left.is_product_distributive() { - left.map(|l| l / number); + if left.map(|l| l / number).is_err() { + return InPlaceDivisionResult::Invalid; + } return InPlaceDivisionResult::Merged; } } else { diff --git a/servo/components/style/values/specified/color.rs b/servo/components/style/values/specified/color.rs index f823ba7d30..289d89e44e 100644 --- a/servo/components/style/values/specified/color.rs +++ b/servo/components/style/values/specified/color.rs @@ -5,12 +5,8 @@ //! Specified color values. use super::AllowQuirks; -use crate::color::component::ColorComponent; -use crate::color::convert::normalize_hue; -use crate::color::parsing::{ - self, ColorParser, FromParsedColor, NumberOrAngle, NumberOrPercentage, -}; -use crate::color::{mix::ColorInterpolationMethod, AbsoluteColor, ColorSpace}; +use crate::color::mix::ColorInterpolationMethod; +use crate::color::{parsing, AbsoluteColor, ColorSpace}; use crate::media_queries::Device; use crate::parser::{Parse, ParserContext}; use crate::values::computed::{Color as ComputedColor, Context, ToComputedValue}; @@ -19,8 +15,7 @@ use crate::values::generics::color::{ }; use crate::values::specified::Percentage; use crate::values::{normalize, CustomIdent}; -use cssparser::color::OPAQUE; -use cssparser::{color::PredefinedColorSpace, BasicParseErrorKind, ParseErrorKind, Parser, Token}; +use cssparser::{BasicParseErrorKind, ParseErrorKind, Parser, Token}; use std::fmt::{self, Write}; use std::io::Write as IoWrite; use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError, StyleParseErrorKind}; @@ -429,199 +424,6 @@ impl SystemColor { } } -impl From> for Option { - fn from(value: ColorComponent) -> Self { - match value { - ColorComponent::None => None, - ColorComponent::Value(value) => Some(value), - } - } -} - -impl ColorComponent { - #[inline] - fn into_alpha(self) -> Option { - 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( - red: ColorComponent, - green: ColorComponent, - blue: ColorComponent, - alpha: ColorComponent, - ) -> 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: ColorComponent, - saturation: ColorComponent, - lightness: ColorComponent, - alpha: ColorComponent, - ) -> Self { - // 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: ColorComponent, - whiteness: ColorComponent, - blackness: ColorComponent, - alpha: ColorComponent, - ) -> Self { - // 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: ColorComponent, - a: ColorComponent, - b: ColorComponent, - alpha: ColorComponent, - ) -> Self { - // 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: ColorComponent, - chroma: ColorComponent, - hue: ColorComponent, - alpha: ColorComponent, - ) -> Self { - // 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: ColorComponent, - a: ColorComponent, - b: ColorComponent, - alpha: ColorComponent, - ) -> Self { - // 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: ColorComponent, - chroma: ColorComponent, - hue: ColorComponent, - alpha: ColorComponent, - ) -> Self { - // 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: ColorComponent, - c2: ColorComponent, - c3: ColorComponent, - alpha: ColorComponent, - ) -> Self { - 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() - } -} - /// Whether to preserve authored colors during parsing. That's useful only if we /// plan to serialize the color back. #[derive(Copy, Clone)] @@ -658,8 +460,7 @@ impl Color { }, }; - let color_parser = ColorParser { context: &context }; - match input.try_parse(|i| parsing::parse_color_with(&color_parser, i)) { + match input.try_parse(|i| parsing::parse_color_with(context, i)) { Ok(mut color) => { if let Color::Absolute(ref mut absolute) = color { // Because we can't set the `authored` value at construction time, we have to set it @@ -827,12 +628,9 @@ impl Color { loc: &cssparser::SourceLocation, ) -> Result> { match cssparser::color::parse_hash_color(bytes) { - Ok((r, g, b, a)) => Ok(Self::from_rgba( - r.into(), - g.into(), - b.into(), - ColorComponent::Value(NumberOrPercentage::Number { value: a }), - )), + Ok((r, g, b, a)) => Ok(Self::from_absolute_color(AbsoluteColor::srgb_legacy( + r, g, b, a, + ))), Err(()) => Err(loc.new_custom_error(StyleParseErrorKind::UnspecifiedError)), } } diff --git a/servo/components/style/values/specified/counters.rs b/servo/components/style/values/specified/counters.rs index 7760be91d7..6e41497caf 100644 --- a/servo/components/style/values/specified/counters.rs +++ b/servo/components/style/values/specified/counters.rs @@ -192,29 +192,33 @@ impl Parse for Content { return Ok(generics::Content::None); } - let mut content = vec![]; - let mut has_alt_content = false; + let mut items = thin_vec::ThinVec::new(); + let mut alt_start = None; loop { - { + if alt_start.is_none() { if let Ok(image) = input.try_parse(|i| Image::parse_forbid_none(context, i)) { - content.push(generics::ContentItem::Image(image)); + items.push(generics::ContentItem::Image(image)); continue; } } - match input.next() { - Ok(&Token::QuotedString(ref value)) => { - content.push(generics::ContentItem::String( + let Ok(t) = input.next() else { break }; + match *t { + Token::QuotedString(ref value) => { + items.push(generics::ContentItem::String( value.as_ref().to_owned().into(), )); }, - Ok(&Token::Function(ref name)) => { + Token::Function(ref name) => { + // FIXME(emilio): counter() / counters() should be valid per spec past + // the alt marker, but it's likely non-trivial to support and other + // browsers don't support it either, so restricting it for now. let result = match_ignore_ascii_case! { &name, - "counter" => input.parse_nested_block(|input| { + "counter" if alt_start.is_none() => input.parse_nested_block(|input| { let name = CustomIdent::parse(input, &[])?; let style = Content::parse_counter_style(context, input); Ok(generics::ContentItem::Counter(name, style)) }), - "counters" => input.parse_nested_block(|input| { + "counters" if alt_start.is_none() => input.parse_nested_block(|input| { let name = CustomIdent::parse(input, &[])?; input.expect_comma()?; let separator = input.expect_string()?.as_ref().to_owned().into(); @@ -232,17 +236,16 @@ impl Parse for Content { )) } }?; - content.push(result); + items.push(result); }, - Ok(&Token::Ident(ref ident)) => { - content.push(match_ignore_ascii_case! { &ident, + Token::Ident(ref ident) if alt_start.is_none() => { + items.push(match_ignore_ascii_case! { &ident, "open-quote" => generics::ContentItem::OpenQuote, "close-quote" => generics::ContentItem::CloseQuote, "no-open-quote" => generics::ContentItem::NoOpenQuote, "no-close-quote" => generics::ContentItem::NoCloseQuote, #[cfg(feature = "gecko")] - "-moz-alt-content" => { - has_alt_content = true; + "-moz-alt-content" if context.in_ua_sheet() => { generics::ContentItem::MozAltContent }, "-moz-label-content" if context.chrome_rules_enabled() => { @@ -256,17 +259,26 @@ impl Parse for Content { } }); }, - Err(_) => break, - Ok(t) => { + Token::Delim('/') + if alt_start.is_none() && + !items.is_empty() && + static_prefs::pref!("layout.css.content.alt-text.enabled") => + { + alt_start = Some(items.len()); + }, + ref t => { let t = t.clone(); return Err(input.new_unexpected_token_error(t)); }, } } - // We don't allow to parse `-moz-alt-content` in multiple positions. - if content.is_empty() || (has_alt_content && content.len() != 1) { + if items.is_empty() { return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); } - Ok(generics::Content::Items(content.into())) + let alt_start = alt_start.unwrap_or(items.len()); + Ok(generics::Content::Items(generics::GenericContentItems { + items, + alt_start, + })) } } -- cgit v1.2.3