tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 6b72f0a4301abfbd2bad47524e87e22503edbdd5
parent b2cd5963c99ad6f059b2573a77701cab4da7dc9f
Author: Diego Escalante <descalante@mozilla.com>
Date:   Wed, 17 Dec 2025 15:00:42 +0000

Bug 1986631 - Implement support for Type(<syntax>) and handle default as raw-string. r=firefox-style-system-reviewers,emilio

Differential Revision: https://phabricator.services.mozilla.com/D275887

Diffstat:
Mservo/components/style/custom_properties.rs | 54++++++++++++++++++++++++++++++++++++++++++++++++------
Mservo/components/style/properties_and_values/syntax/data_type.rs | 2+-
Mservo/components/style/properties_and_values/syntax/mod.rs | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
3 files changed, 131 insertions(+), 13 deletions(-)

diff --git a/servo/components/style/custom_properties.rs b/servo/components/style/custom_properties.rs @@ -17,7 +17,7 @@ use crate::properties::{ }; use crate::properties_and_values::{ registry::PropertyRegistrationData, - syntax::data_type::DependentDataTypes, + syntax::{data_type::DependentDataTypes, Descriptor}, value::{ AllowComputationallyDependent, ComputedValue as ComputedRegisteredValue, SpecifiedValue as SpecifiedRegisteredValue, @@ -473,6 +473,13 @@ enum SubstitutionFunctionKind { Attr, } +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem, Parse)] +enum AttributeType { + None, + Type(Descriptor), + Unit, +} + #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] struct VariableFallback { start: num::NonZeroUsize, @@ -486,6 +493,7 @@ struct SubstitutionFunctionReference { start: usize, end: usize, fallback: Option<VariableFallback>, + attribute_syntax: AttributeType, prev_token_type: TokenSerializationType, next_token_type: TokenSerializationType, substitution_kind: SubstitutionFunctionKind, @@ -831,6 +839,19 @@ fn parse_declaration_value_block<'i, 't>( name.as_ref() }); + let mut attribute_syntax = AttributeType::None; + if substitution_kind == SubstitutionFunctionKind::Attr + && input + .try_parse(|input| input.expect_function_matching("type")) + .is_ok() + { + // TODO(descalante): determine what to do for `type(garbage)` bug 2006626 + attribute_syntax = input + .parse_nested_block(Descriptor::from_css_parser) + .ok() + .map_or(AttributeType::None, AttributeType::Type); + } + // We want the order of the references to match source order. So we need to reserve our slot // now, _before_ parsing our fallback. Note that we don't care if parsing fails after all, since // if this fails we discard the whole result anyways. @@ -845,6 +866,7 @@ fn parse_declaration_value_block<'i, 't>( next_token_type: TokenSerializationType::Nothing, // To be fixed up after parsing fallback. fallback: None, + attribute_syntax, substitution_kind: substitution_kind.clone(), }); @@ -2109,6 +2131,12 @@ fn do_substitute_chunk<'a>( Ok(Substitution::from_value(substituted)) } +fn quoted_css_string(src: &str) -> String { + let mut dest = String::with_capacity(src.len() + 2); + cssparser::serialize_string(src, &mut dest).unwrap(); + dest +} + fn substitute_one_reference<'a>( css: &'a str, url_data: &UrlExtraData, @@ -2135,12 +2163,25 @@ fn substitute_one_reference<'a>( }, SubstitutionFunctionKind::Attr => attr_provider .get_attr(AtomIdent::cast(&reference.name)) - .map(|attr| { - Substitution::new( - Cow::Owned(attr), - TokenSerializationType::Nothing, - TokenSerializationType::Nothing, + .and_then(|attr| { + let AttributeType::Type(syntax) = &reference.attribute_syntax else { + return Some(Substitution::new( + Cow::Owned(quoted_css_string(&attr)), + TokenSerializationType::Nothing, + TokenSerializationType::Nothing, + )); + }; + let mut input = ParserInput::new(&attr); + let mut parser = Parser::new(&mut input); + let value = SpecifiedRegisteredValue::parse( + &mut parser, + syntax, + url_data, + AllowComputationallyDependent::Yes, ) + .ok()?; + let value = value.to_computed_value(computed_context); + Some(Substitution::from_value(value.to_variable_value())) }), }; @@ -2149,6 +2190,7 @@ fn substitute_one_reference<'a>( .next_if(|next_ref| next_ref.end <= reference.end) .is_some() {} + return Ok(s); } diff --git a/servo/components/style/properties_and_values/syntax/data_type.rs b/servo/components/style/properties_and_values/syntax/data_type.rs @@ -22,7 +22,7 @@ bitflags! { } /// <https://drafts.css-houdini.org/css-properties-values-api-1/#supported-names> -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToShmem)] pub enum DataType { /// Any valid `<length>` value Length, diff --git a/servo/components/style/properties_and_values/syntax/mod.rs b/servo/components/style/properties_and_values/syntax/mod.rs @@ -12,7 +12,7 @@ use std::{borrow::Cow, fmt::Write}; use crate::derives::*; use crate::parser::{Parse, ParserContext}; use crate::values::CustomIdent; -use cssparser::{Parser as CSSParser, ParserInput as CSSParserInput}; +use cssparser::{Parser as CSSParser, ParserInput as CSSParserInput, Token}; use style_traits::{ CssWriter, ParseError as StyleParseError, PropertySyntaxParseError as ParseError, StyleParseErrorKind, ToCss, @@ -24,7 +24,7 @@ mod ascii; pub mod data_type; /// <https://drafts.css-houdini.org/css-properties-values-api-1/#parsing-syntax> -#[derive(Debug, Clone, Default, MallocSizeOf, PartialEq)] +#[derive(Debug, Clone, Default, MallocSizeOf, PartialEq, ToShmem)] pub struct Descriptor { /// The parsed components, if any. /// TODO: Could be a Box<[]> if that supported const construction. @@ -54,6 +54,82 @@ impl Descriptor { self.specified.as_deref() } + /// Parse a syntax descriptor from a stream of tokens + /// https://drafts.csswg.org/css-values-5/#typedef-syntax + #[inline] + pub fn from_css_parser<'i>(input: &mut CSSParser<'i, '_>) -> Result<Self, StyleParseError<'i>> { + //TODO(bug 2006624): Should also accept <syntax-string> + let mut components = vec![]; + loop { + let name = Self::try_parse_component_name(input).map_err(|err| { + input.new_custom_error(StyleParseErrorKind::PropertySyntaxField(err)) + })?; + + let multiplier = if name.is_pre_multiplied() { + None + } else { + Self::try_parse_multiplier(input) + }; + + let component = Component { multiplier, name }; + components.push(component); + let Ok(delim) = input.next() else { break }; + + if delim != &Token::Delim('|') { + return Err( + input.new_custom_error(StyleParseErrorKind::PropertySyntaxField( + ParseError::ExpectedPipeBetweenComponents, + )), + ); + } + } + + Ok(Self { + components, + specified: None, + }) + } + + fn try_parse_multiplier<'i>(input: &mut CSSParser<'i, '_>) -> Option<Multiplier> { + input + .try_parse(|input| { + let next = input.next().map_err(|_| ())?; + match next { + Token::Delim('+') => Ok(Multiplier::Space), + Token::Delim('#') => Ok(Multiplier::Comma), + _ => Err(()), + } + }) + .ok() + } + + fn try_parse_component_name<'i>( + input: &mut CSSParser<'i, '_>, + ) -> Result<ComponentName, ParseError> { + if input.try_parse(|input| input.expect_delim('<')).is_ok() { + let name = Self::parse_component_data_type_name(input)?; + input + .expect_delim('>') + .map_err(|_| ParseError::UnclosedDataTypeName)?; + Ok(ComponentName::DataType(name)) + } else { + input.try_parse(|input| { + let name = CustomIdent::parse(input, &[]).map_err(|_| ParseError::InvalidName)?; + Ok(ComponentName::Ident(name)) + }) + } + } + + fn parse_component_data_type_name<'i>( + input: &mut CSSParser<'i, '_>, + ) -> Result<DataType, ParseError> { + input + .expect_ident() + .ok() + .and_then(|n| DataType::from_str(n)) + .ok_or(ParseError::UnknownDataTypeName) + } + /// Parse a syntax descriptor. /// https://drafts.css-houdini.org/css-properties-values-api-1/#consume-a-syntax-definition pub fn from_str(css: &str, save_specified: bool) -> Result<Self, ParseError> { @@ -88,9 +164,9 @@ impl Descriptor { // nulls in the parser specially. let mut components = vec![]; { - let mut parser = Parser::new(input, &mut components); + let mut input = Parser::new(input, &mut components); // 5. Repeatedly consume the next input code point from stream. - parser.parse()?; + input.parse()?; } Ok(Self { components, @@ -174,7 +250,7 @@ impl ToCss for Multiplier { } /// <https://drafts.css-houdini.org/css-properties-values-api-1/#syntax-component> -#[derive(Clone, Debug, MallocSizeOf, PartialEq)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] pub struct Component { name: ComponentName, multiplier: Option<Multiplier>, @@ -220,7 +296,7 @@ impl ToCss for Component { } /// <https://drafts.css-houdini.org/css-properties-values-api-1/#syntax-component-name> -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)] pub enum ComponentName { /// <https://drafts.css-houdini.org/css-properties-values-api-1/#data-type-name> DataType(DataType),