style: [css-nesting] Update cssparser again

This changes the cssparser setup to:

  * Avoid having to do copies of the ParsingContext all over the place,
    which is useful because I plan to stash more nesting state in there.

  * Use the new RuleBodyParser which allows parsing qualified rules,
    declarations, and so on. Though we still don't use this anywhere.

The next step is to join NestedRuleParser and PropertyDeclarationParser,
so that we can parse declarations in a lot of the nested rules as well.

Differential Revision: https://phabricator.services.mozilla.com/D178053
This commit is contained in:
Emilio Cobos Álvarez 2023-05-16 18:02:52 +00:00 committed by Martin Robinson
parent 32f1989a5c
commit 920a1c1f08
15 changed files with 336 additions and 336 deletions

View file

@ -13,7 +13,7 @@ use crate::str::CssStringWriter;
use crate::values::specified::Integer; use crate::values::specified::Integer;
use crate::values::CustomIdent; use crate::values::CustomIdent;
use crate::Atom; use crate::Atom;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, QualifiedRuleParser}; use cssparser::{AtRuleParser, RuleBodyParser, RuleBodyItemParser, DeclarationParser, QualifiedRuleParser};
use cssparser::{CowRcStr, Parser, SourceLocation, Token}; use cssparser::{CowRcStr, Parser, SourceLocation, Token};
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
@ -86,11 +86,11 @@ pub fn parse_counter_style_body<'i, 't>(
let start = input.current_source_location(); let start = input.current_source_location();
let mut rule = CounterStyleRuleData::empty(name, location); let mut rule = CounterStyleRuleData::empty(name, location);
{ {
let parser = CounterStyleRuleParser { let mut parser = CounterStyleRuleParser {
context: context, context,
rule: &mut rule, rule: &mut rule,
}; };
let mut iter = DeclarationListParser::new(input, parser); let mut iter = RuleBodyParser::new(input, &mut parser);
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
if let Err((error, slice)) = declaration { if let Err((error, slice)) = declaration {
let location = error.location; let location = error.location;
@ -159,6 +159,11 @@ impl<'a, 'b, 'i> QualifiedRuleParser<'i> for CounterStyleRuleParser<'a, 'b> {
type Error = StyleParseErrorKind<'i>; type Error = StyleParseErrorKind<'i>;
} }
impl<'a, 'b, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>> for CounterStyleRuleParser<'a, 'b> {
fn parse_qualified(&self) -> bool { false }
fn parse_declarations(&self) -> bool { true }
}
macro_rules! checker { macro_rules! checker {
($self:ident._($value:ident)) => {}; ($self:ident._($value:ident)) => {};
($self:ident. $checker:ident($value:ident)) => { ($self:ident. $checker:ident($value:ident)) => {
@ -219,15 +224,17 @@ macro_rules! counter_style_descriptors {
type Declaration = (); type Declaration = ();
type Error = StyleParseErrorKind<'i>; type Error = StyleParseErrorKind<'i>;
fn parse_value<'t>(&mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't>) fn parse_value<'t>(
-> Result<(), ParseError<'i>> { &mut self,
name: CowRcStr<'i>,
input: &mut Parser<'i, 't>,
) -> Result<(), ParseError<'i>> {
match_ignore_ascii_case! { &*name, match_ignore_ascii_case! { &*name,
$( $(
$name => { $name => {
// DeclarationParser also calls parse_entirely // DeclarationParser also calls parse_entirely so wed normally not
// so wed normally not need to, // need to, but in this case we do because we set the value as a side
// but in this case we do because we set the value as a side effect // effect rather than returning it.
// rather than returning it.
let value = input.parse_entirely(|i| Parse::parse(self.context, i))?; let value = input.parse_entirely(|i| Parse::parse(self.context, i))?;
self.rule.$ident = Some(value) self.rule.$ident = Some(value)
}, },

View file

@ -27,8 +27,8 @@ use crate::values::specified::NonNegativePercentage;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use cssparser::UnicodeRange; use cssparser::UnicodeRange;
use cssparser::{ use cssparser::{
AtRuleParser, CowRcStr, DeclarationListParser, DeclarationParser, Parser, QualifiedRuleParser, AtRuleParser, CowRcStr, RuleBodyParser, RuleBodyItemParser, DeclarationParser, Parser,
SourceLocation, QualifiedRuleParser, SourceLocation,
}; };
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
@ -470,11 +470,11 @@ pub fn parse_font_face_block(
) -> FontFaceRuleData { ) -> FontFaceRuleData {
let mut rule = FontFaceRuleData::empty(location); let mut rule = FontFaceRuleData::empty(location);
{ {
let parser = FontFaceRuleParser { let mut parser = FontFaceRuleParser {
context: context, context,
rule: &mut rule, rule: &mut rule,
}; };
let mut iter = DeclarationListParser::new(input, parser); let mut iter = RuleBodyParser::new(input, &mut parser);
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
if let Err((error, slice)) = declaration { if let Err((error, slice)) = declaration {
let location = error.location; let location = error.location;
@ -566,6 +566,11 @@ impl<'a, 'b, 'i> QualifiedRuleParser<'i> for FontFaceRuleParser<'a, 'b> {
type Error = StyleParseErrorKind<'i>; type Error = StyleParseErrorKind<'i>;
} }
impl<'a, 'b, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>> for FontFaceRuleParser<'a, 'b> {
fn parse_qualified(&self) -> bool { false }
fn parse_declarations(&self) -> bool { true }
}
fn font_tech_enabled() -> bool { fn font_tech_enabled() -> bool {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
return static_prefs::pref!("layout.css.font-tech.enabled"); return static_prefs::pref!("layout.css.font-tech.enabled");

View file

@ -9,6 +9,7 @@ use crate::error_reporting::{ContextualParseError, ParseErrorReporter};
use crate::stylesheets::{CssRuleType, Namespaces, Origin, UrlExtraData}; use crate::stylesheets::{CssRuleType, Namespaces, Origin, UrlExtraData};
use crate::use_counters::UseCounters; use crate::use_counters::UseCounters;
use cssparser::{Parser, SourceLocation, UnicodeRange}; use cssparser::{Parser, SourceLocation, UnicodeRange};
use std::borrow::Cow;
use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator}; use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
/// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko. /// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko.
@ -53,7 +54,7 @@ pub struct ParserContext<'a> {
/// The active error reporter, or none if error reporting is disabled. /// The active error reporter, or none if error reporting is disabled.
error_reporter: Option<&'a dyn ParseErrorReporter>, error_reporter: Option<&'a dyn ParseErrorReporter>,
/// The currently active namespaces. /// The currently active namespaces.
pub namespaces: Option<&'a Namespaces>, pub namespaces: Cow<'a, Namespaces>,
/// The use counters we want to record while parsing style rules, if any. /// The use counters we want to record while parsing style rules, if any.
pub use_counters: Option<&'a UseCounters>, pub use_counters: Option<&'a UseCounters>,
} }
@ -67,6 +68,7 @@ impl<'a> ParserContext<'a> {
rule_type: Option<CssRuleType>, rule_type: Option<CssRuleType>,
parsing_mode: ParsingMode, parsing_mode: ParsingMode,
quirks_mode: QuirksMode, quirks_mode: QuirksMode,
namespaces: Cow<'a, Namespaces>,
error_reporter: Option<&'a dyn ParseErrorReporter>, error_reporter: Option<&'a dyn ParseErrorReporter>,
use_counters: Option<&'a UseCounters>, use_counters: Option<&'a UseCounters>,
) -> Self { ) -> Self {
@ -77,29 +79,17 @@ impl<'a> ParserContext<'a> {
parsing_mode, parsing_mode,
quirks_mode, quirks_mode,
error_reporter, error_reporter,
namespaces: None, namespaces,
use_counters, use_counters,
} }
} }
/// Create a parser context based on a previous context, but with a modified /// Temporarily sets the rule_type and executes the callback function, returning its result.
/// rule type. pub fn nest_for_rule<R>(&mut self, rule_type: CssRuleType, cb: impl FnOnce(&mut Self) -> R) -> R {
#[inline] let old_rule_type = std::mem::replace(&mut self.rule_type, Some(rule_type));
pub fn new_with_rule_type( let r = cb(self);
context: &'a ParserContext, self.rule_type = old_rule_type;
rule_type: CssRuleType, r
namespaces: &'a Namespaces,
) -> ParserContext<'a> {
Self {
stylesheet_origin: context.stylesheet_origin,
url_data: context.url_data,
rule_type: Some(rule_type),
parsing_mode: context.parsing_mode,
quirks_mode: context.quirks_mode,
namespaces: Some(namespaces),
error_reporter: context.error_reporter,
use_counters: context.use_counters,
}
} }
/// Whether we're in a @page rule. /// Whether we're in a @page rule.

View file

@ -26,8 +26,8 @@ use crate::str::{CssString, CssStringWriter};
use crate::stylesheets::{layer_rule::LayerOrder, CssRuleType, Origin, UrlExtraData}; use crate::stylesheets::{layer_rule::LayerOrder, CssRuleType, Origin, UrlExtraData};
use crate::values::computed::Context; use crate::values::computed::Context;
use cssparser::{ use cssparser::{
parse_important, AtRuleParser, CowRcStr, DeclarationListParser, DeclarationParser, Delimiter, parse_important, AtRuleParser, CowRcStr, DeclarationParser, Delimiter, ParseErrorKind, Parser,
ParseErrorKind, Parser, ParserInput, QualifiedRuleParser, ParserInput, QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser,
}; };
use itertools::Itertools; use itertools::Itertools;
use selectors::SelectorList; use selectors::SelectorList;
@ -582,8 +582,9 @@ impl PropertyDeclarationBlock {
.all_shorthand .all_shorthand
.declarations() .declarations()
.any(|decl| { .any(|decl| {
!self.contains(decl.id()) || !self.contains(decl.id())
self.declarations || self
.declarations
.iter() .iter()
.enumerate() .enumerate()
.find(|&(_, ref d)| d.id() == decl.id()) .find(|&(_, ref d)| d.id() == decl.id())
@ -625,9 +626,9 @@ impl PropertyDeclarationBlock {
} }
return DeclarationUpdate::UpdateInPlace { pos }; return DeclarationUpdate::UpdateInPlace { pos };
} }
if !needs_append && if !needs_append
id.logical_group() == Some(logical_group) && && id.logical_group() == Some(logical_group)
id.is_logical() != longhand_id.is_logical() && id.is_logical() != longhand_id.is_logical()
{ {
needs_append = true; needs_append = true;
} }
@ -1292,6 +1293,7 @@ pub fn parse_style_attribute(
Some(rule_type), Some(rule_type),
ParsingMode::DEFAULT, ParsingMode::DEFAULT,
quirks_mode, quirks_mode,
/* namespaces = */ Default::default(),
error_reporter, error_reporter,
None, None,
); );
@ -1322,6 +1324,7 @@ pub fn parse_one_declaration_into(
Some(rule_type), Some(rule_type),
parsing_mode, parsing_mode,
quirks_mode, quirks_mode,
/* namespaces = */ Default::default(),
error_reporter, error_reporter,
None, None,
); );
@ -1411,6 +1414,12 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> {
} }
} }
impl<'a, 'b, 'i> RuleBodyItemParser<'i, Importance, StyleParseErrorKind<'i>> for PropertyDeclarationParser<'a, 'b> {
fn parse_declarations(&self) -> bool { true }
// TODO(emilio): Nesting.
fn parse_qualified(&self) -> bool { false }
}
type SmallParseErrorVec<'i> = SmallVec<[(ParseError<'i>, &'i str, Option<PropertyId>); 2]>; type SmallParseErrorVec<'i> = SmallVec<[(ParseError<'i>, &'i str, Option<PropertyId>); 2]>;
fn alias_of_known_property(name: &str) -> Option<PropertyId> { fn alias_of_known_property(name: &str) -> Option<PropertyId> {
@ -1498,12 +1507,12 @@ pub fn parse_property_declaration_list(
) -> PropertyDeclarationBlock { ) -> PropertyDeclarationBlock {
let mut declarations = SourcePropertyDeclaration::new(); let mut declarations = SourcePropertyDeclaration::new();
let mut block = PropertyDeclarationBlock::new(); let mut block = PropertyDeclarationBlock::new();
let parser = PropertyDeclarationParser { let mut parser = PropertyDeclarationParser {
context, context,
last_parsed_property_id: None, last_parsed_property_id: None,
declarations: &mut declarations, declarations: &mut declarations,
}; };
let mut iter = DeclarationListParser::new(input, parser); let mut iter = RuleBodyParser::new(input, &mut parser);
let mut errors = SmallParseErrorVec::new(); let mut errors = SmallParseErrorVec::new();
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
match declaration { match declaration {

View file

@ -1769,6 +1769,7 @@ impl UnparsedValue {
None, None,
ParsingMode::DEFAULT, ParsingMode::DEFAULT,
quirks_mode, quirks_mode,
/* namespaces = */ Default::default(),
None, None,
None, None,
); );

View file

@ -19,8 +19,8 @@ use crate::values::computed::font::FamilyName;
use crate::values::serialize_atom_identifier; use crate::values::serialize_atom_identifier;
use crate::Atom; use crate::Atom;
use cssparser::{ use cssparser::{
AtRuleParser, BasicParseErrorKind, CowRcStr, DeclarationListParser, DeclarationParser, Parser, AtRuleParser, BasicParseErrorKind, CowRcStr, RuleBodyParser, RuleBodyItemParser, Parser,
ParserState, QualifiedRuleParser, RuleListParser, SourceLocation, Token, ParserState, QualifiedRuleParser, DeclarationParser, SourceLocation, Token,
}; };
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
@ -215,13 +215,21 @@ where
let value = input.parse_entirely(|i| T::parse(self.context, i))?; let value = input.parse_entirely(|i| T::parse(self.context, i))?;
let new = FFVDeclaration { let new = FFVDeclaration {
name: Atom::from(&*name), name: Atom::from(&*name),
value: value, value,
}; };
update_or_push(&mut self.declarations, new); update_or_push(&mut self.declarations, new);
Ok(()) Ok(())
} }
} }
impl<'a, 'b, 'i, T> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>> for FFVDeclarationsParser<'a, 'b, T>
where
T: Parse,
{
fn parse_declarations(&self) -> bool { true }
fn parse_qualified(&self) -> bool { false }
}
macro_rules! font_feature_values_blocks { macro_rules! font_feature_values_blocks {
( (
blocks = [ blocks = [
@ -265,12 +273,11 @@ macro_rules! font_feature_values_blocks {
location: SourceLocation, location: SourceLocation,
) -> Self { ) -> Self {
let mut rule = FontFeatureValuesRule::new(family_names, location); let mut rule = FontFeatureValuesRule::new(family_names, location);
let mut parser = FontFeatureValuesRuleParser {
{ context,
let mut iter = RuleListParser::new_for_nested_rule(input, FontFeatureValuesRuleParser {
context: context,
rule: &mut rule, rule: &mut rule,
}); };
let mut iter = RuleBodyParser::new(input, &mut parser);
while let Some(result) = iter.next() { while let Some(result) = iter.next() {
if let Err((error, slice)) = result { if let Err((error, slice)) = result {
let location = error.location; let location = error.location;
@ -278,7 +285,6 @@ macro_rules! font_feature_values_blocks {
context.log_css_error(location, error); context.log_css_error(location, error);
} }
} }
}
rule rule
} }
@ -348,9 +354,8 @@ macro_rules! font_feature_values_blocks {
/// Updates with new value if same `ident` exists, otherwise pushes to the vector. /// Updates with new value if same `ident` exists, otherwise pushes to the vector.
fn update_or_push<T>(vec: &mut Vec<FFVDeclaration<T>>, element: FFVDeclaration<T>) { fn update_or_push<T>(vec: &mut Vec<FFVDeclaration<T>>, element: FFVDeclaration<T>) {
let position = vec.iter().position(|ref val| val.name == element.name); if let Some(item) = vec.iter_mut().find(|item| item.name == element.name) {
if let Some(index) = position { item.value = element.value;
vec[index].value = element.value;
} else { } else {
vec.push(element); vec.push(element);
} }
@ -409,12 +414,12 @@ macro_rules! font_feature_values_blocks {
match prelude { match prelude {
$( $(
BlockType::$ident_camel => { BlockType::$ident_camel => {
let parser = FFVDeclarationsParser { let mut parser = FFVDeclarationsParser {
context: &self.context, context: &self.context,
declarations: &mut self.rule.$ident, declarations: &mut self.rule.$ident,
}; };
let mut iter = DeclarationListParser::new(input, parser); let mut iter = RuleBodyParser::new(input, &mut parser);
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
if let Err((error, slice)) = declaration { if let Err((error, slice)) = declaration {
let location = error.location; let location = error.location;
@ -431,6 +436,16 @@ macro_rules! font_feature_values_blocks {
Ok(()) Ok(())
} }
} }
impl<'a, 'i> DeclarationParser<'i> for FontFeatureValuesRuleParser<'a> {
type Declaration = ();
type Error = StyleParseErrorKind<'i>;
}
impl<'a, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>> for FontFeatureValuesRuleParser<'a> {
fn parse_declarations(&self) -> bool { false }
fn parse_qualified(&self) -> bool { true }
}
} }
} }

View file

@ -7,7 +7,6 @@
//! [font-palette-values]: https://drafts.csswg.org/css-fonts/#font-palette-values //! [font-palette-values]: https://drafts.csswg.org/css-fonts/#font-palette-values
use crate::error_reporting::ContextualParseError; use crate::error_reporting::ContextualParseError;
use crate::parser::{Parse, ParserContext};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::gecko_bindings::{ use crate::gecko_bindings::{
bindings::Gecko_AppendPaletteValueHashEntry, bindings::Gecko_AppendPaletteValueHashEntry,
@ -16,20 +15,22 @@ use crate::gecko_bindings::{
structs::gfx::FontPaletteValueSet_PaletteValues_kDark, structs::gfx::FontPaletteValueSet_PaletteValues_kDark,
structs::gfx::FontPaletteValueSet_PaletteValues_kLight, structs::gfx::FontPaletteValueSet_PaletteValues_kLight,
}; };
use crate::parser::{Parse, ParserContext};
use crate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; use crate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use crate::str::CssStringWriter; use crate::str::CssStringWriter;
use crate::stylesheets::font_feature_values_rule::parse_family_name_list;
use crate::values::computed::font::FamilyName; use crate::values::computed::font::FamilyName;
use crate::values::specified::Color as SpecifiedColor; use crate::values::specified::Color as SpecifiedColor;
use crate::values::specified::NonNegativeInteger; use crate::values::specified::NonNegativeInteger;
use crate::values::DashedIdent; use crate::values::DashedIdent;
use cssparser::{AtRuleParser, CowRcStr}; use cssparser::{
use cssparser::{DeclarationParser, DeclarationListParser, Parser}; AtRuleParser, CowRcStr, DeclarationParser, Parser, QualifiedRuleParser, RuleBodyItemParser,
use cssparser::{QualifiedRuleParser, SourceLocation}; RuleBodyParser, SourceLocation,
use std::fmt::{self, Write}; };
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
use style_traits::{Comma, OneOrMoreSeparated};
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
use crate::stylesheets::font_feature_values_rule::parse_family_name_list; use std::fmt::{self, Write};
use style_traits::{Comma, OneOrMoreSeparated};
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
@ -121,20 +122,19 @@ impl FontPaletteValuesRule {
location: SourceLocation, location: SourceLocation,
) -> Self { ) -> Self {
let mut rule = FontPaletteValuesRule::new(name, location); let mut rule = FontPaletteValuesRule::new(name, location);
{ let mut parser = FontPaletteValuesDeclarationParser {
let parser = FontPaletteValuesDeclarationParser { context,
context: context,
rule: &mut rule, rule: &mut rule,
}; };
let mut iter = DeclarationListParser::new(input, parser); let mut iter = RuleBodyParser::new(input, &mut parser);
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
if let Err((error, slice)) = declaration { if let Err((error, slice)) = declaration {
let location = error.location; let location = error.location;
let error = ContextualParseError::UnsupportedFontPaletteValuesDescriptor(slice, error); let error =
ContextualParseError::UnsupportedFontPaletteValuesDescriptor(slice, error);
context.log_css_error(location, error); context.log_css_error(location, error);
} }
} }
}
rule rule
} }
@ -167,19 +167,18 @@ impl FontPaletteValuesRule {
for ref family in self.family_names.iter() { for ref family in self.family_names.iter() {
let family = family.name.to_ascii_lowercase(); let family = family.name.to_ascii_lowercase();
let palette_values = unsafe { let palette_values = unsafe {
Gecko_AppendPaletteValueHashEntry( Gecko_AppendPaletteValueHashEntry(dest, family.as_ptr(), self.name.0.as_ptr())
dest,
family.as_ptr(),
self.name.0.as_ptr()
)
}; };
if let Some(base_palette) = &self.base_palette { if let Some(base_palette) = &self.base_palette {
unsafe { unsafe {
Gecko_SetFontPaletteBase(palette_values, match &base_palette { Gecko_SetFontPaletteBase(
palette_values,
match &base_palette {
FontPaletteBase::Light => FontPaletteValueSet_PaletteValues_kLight, FontPaletteBase::Light => FontPaletteValueSet_PaletteValues_kLight,
FontPaletteBase::Dark => FontPaletteValueSet_PaletteValues_kDark, FontPaletteBase::Dark => FontPaletteValueSet_PaletteValues_kDark,
FontPaletteBase::Index(i) => i.0.value() as i32, FontPaletteBase::Index(i) => i.0.value() as i32,
}); },
);
} }
} }
for c in &self.override_colors { for c in &self.override_colors {
@ -256,3 +255,14 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for FontPaletteValuesDeclarationParser<'a
Ok(()) Ok(())
} }
} }
impl<'a, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>>
for FontPaletteValuesDeclarationParser<'a>
{
fn parse_declarations(&self) -> bool {
true
}
fn parse_qualified(&self) -> bool {
false
}
}

View file

@ -13,7 +13,7 @@ use crate::shared_lock::{
}; };
use crate::str::CssStringWriter; use crate::str::CssStringWriter;
use crate::stylesheets::{ use crate::stylesheets::{
layer_rule::LayerName, stylesheet::Namespaces, supports_rule::SupportsCondition, CssRule, layer_rule::LayerName, supports_rule::SupportsCondition, CssRule,
CssRuleType, StylesheetInDocument, CssRuleType, StylesheetInDocument,
}; };
use crate::values::CssUrl; use crate::values::CssUrl;
@ -243,8 +243,7 @@ impl ImportRule {
/// whole import rule or parse the media query list or what not. /// whole import rule or parse the media query list or what not.
pub fn parse_layer_and_supports<'i, 't>( pub fn parse_layer_and_supports<'i, 't>(
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
context: &ParserContext, context: &mut ParserContext,
namespaces: &Namespaces,
) -> (ImportLayer, Option<ImportSupportsCondition>) { ) -> (ImportLayer, Option<ImportSupportsCondition>) {
let layer = if input let layer = if input
.try_parse(|input| input.expect_ident_matching("layer")) .try_parse(|input| input.expect_ident_matching("layer"))
@ -273,9 +272,9 @@ impl ImportRule {
input input
.try_parse(SupportsCondition::parse_for_import) .try_parse(SupportsCondition::parse_for_import)
.map(|condition| { .map(|condition| {
let eval_context = let enabled = context.nest_for_rule(CssRuleType::Style, |context| {
ParserContext::new_with_rule_type(context, CssRuleType::Style, namespaces); condition.eval(context)
let enabled = condition.eval(&eval_context, namespaces); });
ImportSupportsCondition { condition, enabled } ImportSupportsCondition { condition, enabled }
}) })
.ok() .ok()

View file

@ -19,11 +19,12 @@ use crate::stylesheets::rule_parser::VendorPrefix;
use crate::stylesheets::{CssRuleType, StylesheetContents}; use crate::stylesheets::{CssRuleType, StylesheetContents};
use crate::values::{serialize_percentage, KeyframesName}; use crate::values::{serialize_percentage, KeyframesName};
use cssparser::{ use cssparser::{
parse_one_rule, DeclarationListParser, DeclarationParser, ParserState, SourceLocation, Token, parse_one_rule, AtRuleParser, CowRcStr, DeclarationParser, Parser, ParserInput, ParserState,
QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourceLocation, Token,
}; };
use cssparser::{AtRuleParser, CowRcStr, Parser, ParserInput, QualifiedRuleParser, RuleListParser};
use servo_arc::Arc; use servo_arc::Arc;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::borrow::Cow;
use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss}; use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss};
/// A [`@keyframes`][keyframes] rule. /// A [`@keyframes`][keyframes] rule.
@ -217,16 +218,16 @@ impl Keyframe {
Some(CssRuleType::Keyframe), Some(CssRuleType::Keyframe),
ParsingMode::DEFAULT, ParsingMode::DEFAULT,
parent_stylesheet_contents.quirks_mode, parent_stylesheet_contents.quirks_mode,
Cow::Borrowed(&*namespaces),
None, None,
None, None,
); );
context.namespaces = Some(&*namespaces);
let mut input = ParserInput::new(css); let mut input = ParserInput::new(css);
let mut input = Parser::new(&mut input); let mut input = Parser::new(&mut input);
let mut declarations = SourcePropertyDeclaration::new(); let mut declarations = SourcePropertyDeclaration::new();
let mut rule_parser = KeyframeListParser { let mut rule_parser = KeyframeListParser {
context: &context, context: &mut context,
shared_lock: &lock, shared_lock: &lock,
declarations: &mut declarations, declarations: &mut declarations,
}; };
@ -526,43 +527,39 @@ impl KeyframesAnimation {
/// 40%, 60%, 100% { /// 40%, 60%, 100% {
/// width: 100%; /// width: 100%;
/// } /// }
struct KeyframeListParser<'a> { struct KeyframeListParser<'a, 'b> {
context: &'a ParserContext<'a>, context: &'a mut ParserContext<'b>,
shared_lock: &'a SharedRwLock, shared_lock: &'a SharedRwLock,
declarations: &'a mut SourcePropertyDeclaration, declarations: &'a mut SourcePropertyDeclaration,
} }
/// Parses a keyframe list from CSS input. /// Parses a keyframe list from CSS input.
pub fn parse_keyframe_list( pub fn parse_keyframe_list<'a>(
context: &ParserContext, context: &mut ParserContext<'a>,
input: &mut Parser, input: &mut Parser,
shared_lock: &SharedRwLock, shared_lock: &SharedRwLock,
) -> Vec<Arc<Locked<Keyframe>>> { ) -> Vec<Arc<Locked<Keyframe>>> {
debug_assert!(
context.namespaces.is_some(),
"Parsing a keyframe list from a context without namespaces?"
);
let mut declarations = SourcePropertyDeclaration::new(); let mut declarations = SourcePropertyDeclaration::new();
RuleListParser::new_for_nested_rule( let mut parser = KeyframeListParser {
input,
KeyframeListParser {
context, context,
shared_lock, shared_lock,
declarations: &mut declarations, declarations: &mut declarations,
}, };
) RuleBodyParser::new(input, &mut parser).filter_map(Result::ok) .collect()
.filter_map(Result::ok)
.collect()
} }
impl<'a, 'i> AtRuleParser<'i> for KeyframeListParser<'a> { impl<'a, 'b, 'i> AtRuleParser<'i> for KeyframeListParser<'a, 'b> {
type Prelude = (); type Prelude = ();
type AtRule = Arc<Locked<Keyframe>>; type AtRule = Arc<Locked<Keyframe>>;
type Error = StyleParseErrorKind<'i>; type Error = StyleParseErrorKind<'i>;
} }
impl<'a, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a> { impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeListParser<'a, 'b> {
type Declaration = Arc<Locked<Keyframe>>;
type Error = StyleParseErrorKind<'i>;
}
impl<'a, 'b, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a, 'b> {
type Prelude = KeyframeSelector; type Prelude = KeyframeSelector;
type QualifiedRule = Arc<Locked<Keyframe>>; type QualifiedRule = Arc<Locked<Keyframe>>;
type Error = StyleParseErrorKind<'i>; type Error = StyleParseErrorKind<'i>;
@ -589,18 +586,14 @@ impl<'a, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a> {
start: &ParserState, start: &ParserState,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self::QualifiedRule, ParseError<'i>> { ) -> Result<Self::QualifiedRule, ParseError<'i>> {
let context = ParserContext::new_with_rule_type(
self.context,
CssRuleType::Keyframe,
self.context.namespaces.unwrap(),
);
let parser = KeyframeDeclarationParser {
context: &context,
declarations: self.declarations,
};
let mut iter = DeclarationListParser::new(input, parser);
let mut block = PropertyDeclarationBlock::new(); let mut block = PropertyDeclarationBlock::new();
let declarations = &mut self.declarations;
self.context.nest_for_rule(CssRuleType::Keyframe, |context| {
let mut parser = KeyframeDeclarationParser {
context: &context,
declarations,
};
let mut iter = RuleBodyParser::new(input, &mut parser);
while let Some(declaration) = iter.next() { while let Some(declaration) = iter.next() {
match declaration { match declaration {
Ok(()) => { Ok(()) => {
@ -616,6 +609,7 @@ impl<'a, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a> {
} }
// `parse_important` is not called here, `!important` is not allowed in keyframe blocks. // `parse_important` is not called here, `!important` is not allowed in keyframe blocks.
} }
});
Ok(Arc::new(self.shared_lock.wrap(Keyframe { Ok(Arc::new(self.shared_lock.wrap(Keyframe {
selector, selector,
block: Arc::new(self.shared_lock.wrap(block)), block: Arc::new(self.shared_lock.wrap(block)),
@ -624,6 +618,11 @@ impl<'a, 'i> QualifiedRuleParser<'i> for KeyframeListParser<'a> {
} }
} }
impl<'a, 'b, 'i> RuleBodyItemParser<'i, Arc<Locked<Keyframe>>, StyleParseErrorKind<'i>> for KeyframeListParser<'a, 'b> {
fn parse_qualified(&self) -> bool { true }
fn parse_declarations(&self) -> bool { false }
}
struct KeyframeDeclarationParser<'a, 'b: 'a> { struct KeyframeDeclarationParser<'a, 'b: 'a> {
context: &'a ParserContext<'b>, context: &'a ParserContext<'b>,
declarations: &'a mut SourcePropertyDeclaration, declarations: &'a mut SourcePropertyDeclaration,
@ -668,3 +667,8 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeDeclarationParser<'a, 'b> {
Ok(()) Ok(())
} }
} }
impl<'a, 'b, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>> for KeyframeDeclarationParser<'a, 'b> {
fn parse_qualified(&self) -> bool { false }
fn parse_declarations(&self) -> bool { true }
}

View file

@ -39,6 +39,7 @@ use cssparser::{parse_one_rule, Parser, ParserInput};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf}; use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
use servo_arc::Arc; use servo_arc::Arc;
use std::borrow::Cow;
use std::fmt; use std::fmt;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use std::mem::{self, ManuallyDrop}; use std::mem::{self, ManuallyDrop};
@ -401,12 +402,14 @@ impl CssRule {
allow_import_rules: AllowImportRules, allow_import_rules: AllowImportRules,
) -> Result<Self, RulesMutateError> { ) -> Result<Self, RulesMutateError> {
let url_data = parent_stylesheet_contents.url_data.read(); let url_data = parent_stylesheet_contents.url_data.read();
let namespaces = parent_stylesheet_contents.namespaces.read();
let context = ParserContext::new( let context = ParserContext::new(
parent_stylesheet_contents.origin, parent_stylesheet_contents.origin,
&url_data, &url_data,
None, None,
ParsingMode::DEFAULT, ParsingMode::DEFAULT,
parent_stylesheet_contents.quirks_mode, parent_stylesheet_contents.quirks_mode,
Cow::Borrowed(&*namespaces),
None, None,
None, None,
); );
@ -414,8 +417,6 @@ impl CssRule {
let mut input = ParserInput::new(css); let mut input = ParserInput::new(css);
let mut input = Parser::new(&mut input); let mut input = Parser::new(&mut input);
let mut guard = parent_stylesheet_contents.namespaces.write();
// nested rules are in the body state // nested rules are in the body state
let mut rule_parser = TopLevelRuleParser { let mut rule_parser = TopLevelRuleParser {
context, context,
@ -423,7 +424,6 @@ impl CssRule {
loader, loader,
state, state,
dom_error: None, dom_error: None,
namespaces: &mut *guard,
insert_rule_context: Some(insert_rule_context), insert_rule_context: Some(insert_rule_context),
allow_import_rules, allow_import_rules,
}; };

View file

@ -19,7 +19,6 @@ use crate::stylesheets::font_feature_values_rule::parse_family_name_list;
use crate::stylesheets::import_rule::{ImportRule, ImportLayer, ImportSupportsCondition}; use crate::stylesheets::import_rule::{ImportRule, ImportLayer, ImportSupportsCondition};
use crate::stylesheets::keyframes_rule::parse_keyframe_list; use crate::stylesheets::keyframes_rule::parse_keyframe_list;
use crate::stylesheets::layer_rule::{LayerBlockRule, LayerName, LayerStatementRule}; use crate::stylesheets::layer_rule::{LayerBlockRule, LayerName, LayerStatementRule};
use crate::stylesheets::stylesheet::Namespaces;
use crate::stylesheets::supports_rule::SupportsCondition; use crate::stylesheets::supports_rule::SupportsCondition;
use crate::stylesheets::{ use crate::stylesheets::{
viewport_rule, AllowImportRules, CorsMode, CssRule, CssRuleType, CssRules, DocumentRule, viewport_rule, AllowImportRules, CorsMode, CssRule, CssRuleType, CssRules, DocumentRule,
@ -31,8 +30,8 @@ use crate::values::computed::font::FamilyName;
use crate::values::{CssUrl, CustomIdent, DashedIdent, KeyframesName}; use crate::values::{CssUrl, CustomIdent, DashedIdent, KeyframesName};
use crate::{Namespace, Prefix}; use crate::{Namespace, Prefix};
use cssparser::{ use cssparser::{
AtRuleParser, BasicParseError, BasicParseErrorKind, CowRcStr, Parser, ParserState, AtRuleParser, BasicParseError, BasicParseErrorKind, CowRcStr, DeclarationParser, Parser,
QualifiedRuleParser, RuleListParser, SourcePosition, ParserState, QualifiedRuleParser, RuleBodyParser, RuleBodyItemParser, SourcePosition,
}; };
use selectors::SelectorList; use selectors::SelectorList;
use servo_arc::Arc; use servo_arc::Arc;
@ -83,9 +82,6 @@ pub struct TopLevelRuleParser<'a> {
/// A reference to a stylesheet loader if applicable, for `@import` rules. /// A reference to a stylesheet loader if applicable, for `@import` rules.
pub loader: Option<&'a dyn StylesheetLoader>, pub loader: Option<&'a dyn StylesheetLoader>,
/// The top-level parser context. /// The top-level parser context.
///
/// This won't contain any namespaces, and only nested parsers created with
/// `ParserContext::new_with_rule_type` will.
pub context: ParserContext<'a>, pub context: ParserContext<'a>,
/// The current state of the parser. /// The current state of the parser.
pub state: State, pub state: State,
@ -93,22 +89,17 @@ pub struct TopLevelRuleParser<'a> {
/// place (e.g. an @import rule was found while in the `Body` state). Reset /// place (e.g. an @import rule was found while in the `Body` state). Reset
/// to `false` when `take_had_hierarchy_error` is called. /// to `false` when `take_had_hierarchy_error` is called.
pub dom_error: Option<RulesMutateError>, pub dom_error: Option<RulesMutateError>,
/// The namespace map we use for parsing. Needs to start as `Some()`, and
/// will be taken out after parsing namespace rules, and that reference will
/// be moved to `ParserContext`.
pub namespaces: &'a mut Namespaces,
/// The info we need insert a rule in a list. /// The info we need insert a rule in a list.
pub insert_rule_context: Option<InsertRuleContext<'a>>, pub insert_rule_context: Option<InsertRuleContext<'a>>,
/// Whether @import rules will be allowed. /// Whether @import rules will be allowed.
pub allow_import_rules: AllowImportRules, pub allow_import_rules: AllowImportRules,
} }
impl<'b> TopLevelRuleParser<'b> { impl<'a> TopLevelRuleParser<'a> {
fn nested<'a: 'b>(&'a self) -> NestedRuleParser<'a, 'b> { fn nested<'b>(&'b mut self) -> NestedRuleParser<'b, 'a> {
NestedRuleParser { NestedRuleParser {
shared_lock: self.shared_lock, shared_lock: self.shared_lock,
context: &self.context, context: &mut self.context,
namespaces: &self.namespaces,
} }
} }
@ -241,7 +232,7 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
let url_string = input.expect_url_or_string()?.as_ref().to_owned(); let url_string = input.expect_url_or_string()?.as_ref().to_owned();
let url = CssUrl::parse_from_string(url_string, &self.context, CorsMode::None); let url = CssUrl::parse_from_string(url_string, &self.context, CorsMode::None);
let (layer, supports) = ImportRule::parse_layer_and_supports(input, &self.context, self.namespaces); let (layer, supports) = ImportRule::parse_layer_and_supports(input, &mut self.context);
let media = MediaList::parse(&self.context, input); let media = MediaList::parse(&self.context, input);
let media = Arc::new(self.shared_lock.wrap(media)); let media = Arc::new(self.shared_lock.wrap(media));
@ -334,11 +325,12 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
CssRule::Import(import_rule) CssRule::Import(import_rule)
}, },
AtRulePrelude::Namespace(prefix, url) => { AtRulePrelude::Namespace(prefix, url) => {
let namespaces = self.context.namespaces.to_mut();
let prefix = if let Some(prefix) = prefix { let prefix = if let Some(prefix) = prefix {
self.namespaces.prefixes.insert(prefix.clone(), url.clone()); namespaces.prefixes.insert(prefix.clone(), url.clone());
Some(prefix) Some(prefix)
} else { } else {
self.namespaces.default = Some(url.clone()); namespaces.default = Some(url.clone());
None None
}; };
@ -398,28 +390,27 @@ impl<'a, 'i> QualifiedRuleParser<'i> for TopLevelRuleParser<'a> {
} }
} }
#[derive(Clone)] // shallow, relatively cheap .clone
struct NestedRuleParser<'a, 'b: 'a> { struct NestedRuleParser<'a, 'b: 'a> {
shared_lock: &'a SharedRwLock, shared_lock: &'a SharedRwLock,
context: &'a ParserContext<'b>, context: &'a mut ParserContext<'b>,
namespaces: &'a Namespaces,
} }
impl<'a, 'b> NestedRuleParser<'a, 'b> { impl<'a, 'b> NestedRuleParser<'a, 'b> {
fn nest_for_rule<R>(&mut self, rule_type: CssRuleType, cb: impl FnOnce(&mut Self) -> R) -> R {
let old_rule_type = self.context.rule_type.take();
self.context.rule_type = Some(rule_type);
let r = cb(self);
self.context.rule_type = old_rule_type;
r
}
fn parse_nested_rules( fn parse_nested_rules(
&mut self, &mut self,
input: &mut Parser, input: &mut Parser,
rule_type: CssRuleType, rule_type: CssRuleType,
) -> Arc<Locked<CssRules>> { ) -> Arc<Locked<CssRules>> {
let context = ParserContext::new_with_rule_type(self.context, rule_type, self.namespaces); self.nest_for_rule(rule_type, |parser| {
let mut iter = RuleBodyParser::new(input, parser);
let nested_parser = NestedRuleParser {
shared_lock: self.shared_lock,
context: &context,
namespaces: self.namespaces,
};
let mut iter = RuleListParser::new_for_nested_rule(input, nested_parser);
let mut rules = Vec::new(); let mut rules = Vec::new();
while let Some(result) = iter.next() { while let Some(result) = iter.next() {
match result { match result {
@ -427,11 +418,12 @@ impl<'a, 'b> NestedRuleParser<'a, 'b> {
Err((error, slice)) => { Err((error, slice)) => {
let location = error.location; let location = error.location;
let error = ContextualParseError::InvalidRule(slice, error); let error = ContextualParseError::InvalidRule(slice, error);
self.context.log_css_error(location, error); iter.parser.context.log_css_error(location, error);
}, },
} }
} }
CssRules::new(rules, self.shared_lock) CssRules::new(rules, iter.parser.shared_lock)
})
} }
} }
@ -536,61 +528,45 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
) -> Result<CssRule, ParseError<'i>> { ) -> Result<CssRule, ParseError<'i>> {
match prelude { match prelude {
AtRulePrelude::FontFace => { AtRulePrelude::FontFace => {
let context = ParserContext::new_with_rule_type( self.nest_for_rule(CssRuleType::FontFace, |p| {
self.context, Ok(CssRule::FontFace(Arc::new(p.shared_lock.wrap(
CssRuleType::FontFace, parse_font_face_block(&p.context, input, start.source_location()).into(),
self.namespaces,
);
Ok(CssRule::FontFace(Arc::new(self.shared_lock.wrap(
parse_font_face_block(&context, input, start.source_location()).into(),
)))) ))))
})
}, },
AtRulePrelude::FontFeatureValues(family_names) => { AtRulePrelude::FontFeatureValues(family_names) => {
let context = ParserContext::new_with_rule_type( self.nest_for_rule(CssRuleType::FontFeatureValues, |p| {
self.context, Ok(CssRule::FontFeatureValues(Arc::new(p.shared_lock.wrap(
CssRuleType::FontFeatureValues,
self.namespaces,
);
Ok(CssRule::FontFeatureValues(Arc::new(self.shared_lock.wrap(
FontFeatureValuesRule::parse( FontFeatureValuesRule::parse(
&context, &p.context,
input, input,
family_names, family_names,
start.source_location(), start.source_location(),
), ),
)))) ))))
})
}, },
AtRulePrelude::FontPaletteValues(name) => { AtRulePrelude::FontPaletteValues(name) => {
let context = ParserContext::new_with_rule_type( self.nest_for_rule(CssRuleType::FontPaletteValues, |p| {
self.context, Ok(CssRule::FontPaletteValues(Arc::new(p.shared_lock.wrap(
CssRuleType::FontPaletteValues,
self.namespaces,
);
Ok(CssRule::FontPaletteValues(Arc::new(self.shared_lock.wrap(
FontPaletteValuesRule::parse( FontPaletteValuesRule::parse(
&context, &p.context,
input, input,
name, name,
start.source_location(), start.source_location(),
), ),
)))) ))))
})
}, },
AtRulePrelude::CounterStyle(name) => { AtRulePrelude::CounterStyle(name) => {
let context = ParserContext::new_with_rule_type( self.nest_for_rule(CssRuleType::CounterStyle, |p| {
self.context,
CssRuleType::CounterStyle,
self.namespaces,
);
Ok(CssRule::CounterStyle(Arc::new( Ok(CssRule::CounterStyle(Arc::new(
self.shared_lock.wrap( p.shared_lock.wrap(
parse_counter_style_body(name, &context, input, start.source_location())? parse_counter_style_body(name, &p.context, input, start.source_location())?
.into(), .into(),
), ),
))) )))
})
}, },
AtRulePrelude::Media(media_queries) => { AtRulePrelude::Media(media_queries) => {
Ok(CssRule::Media(Arc::new(self.shared_lock.wrap(MediaRule { Ok(CssRule::Media(Arc::new(self.shared_lock.wrap(MediaRule {
@ -600,13 +576,9 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
})))) }))))
}, },
AtRulePrelude::Supports(condition) => { AtRulePrelude::Supports(condition) => {
let eval_context = ParserContext::new_with_rule_type( let enabled = self.nest_for_rule(CssRuleType::Style, |p| {
self.context, condition.eval(&p.context)
CssRuleType::Style, });
self.namespaces,
);
let enabled = condition.eval(&eval_context, self.namespaces);
Ok(CssRule::Supports(Arc::new(self.shared_lock.wrap( Ok(CssRule::Supports(Arc::new(self.shared_lock.wrap(
SupportsRule { SupportsRule {
condition, condition,
@ -617,40 +589,28 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
)))) ))))
}, },
AtRulePrelude::Viewport => { AtRulePrelude::Viewport => {
let context = ParserContext::new_with_rule_type( self.nest_for_rule(CssRuleType::Viewport, |p| {
self.context,
CssRuleType::Viewport,
self.namespaces,
);
Ok(CssRule::Viewport(Arc::new( Ok(CssRule::Viewport(Arc::new(
self.shared_lock.wrap(ViewportRule::parse(&context, input)?), p.shared_lock.wrap(ViewportRule::parse(&p.context, input)?),
))) )))
})
}, },
AtRulePrelude::Keyframes(name, vendor_prefix) => { AtRulePrelude::Keyframes(name, vendor_prefix) => {
let context = ParserContext::new_with_rule_type( self.nest_for_rule(CssRuleType::Keyframe, |p| {
self.context, Ok(CssRule::Keyframes(Arc::new(p.shared_lock.wrap(
CssRuleType::Keyframes,
self.namespaces,
);
Ok(CssRule::Keyframes(Arc::new(self.shared_lock.wrap(
KeyframesRule { KeyframesRule {
name, name,
keyframes: parse_keyframe_list(&context, input, self.shared_lock), keyframes: parse_keyframe_list(&mut p.context, input, p.shared_lock),
vendor_prefix, vendor_prefix,
source_location: start.source_location(), source_location: start.source_location(),
}, },
)))) ))))
})
}, },
AtRulePrelude::Page(selectors) => { AtRulePrelude::Page(selectors) => {
let context = ParserContext::new_with_rule_type( let declarations = self.nest_for_rule(CssRuleType::Page, |p| {
self.context, parse_property_declaration_list(&p.context, input, None)
CssRuleType::Page, });
self.namespaces,
);
let declarations = parse_property_declaration_list(&context, input, None);
Ok(CssRule::Page(Arc::new(self.shared_lock.wrap(PageRule { Ok(CssRule::Page(Arc::new(self.shared_lock.wrap(PageRule {
selectors, selectors,
block: Arc::new(self.shared_lock.wrap(declarations)), block: Arc::new(self.shared_lock.wrap(declarations)),
@ -763,7 +723,7 @@ impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> {
) -> Result<Self::Prelude, ParseError<'i>> { ) -> Result<Self::Prelude, ParseError<'i>> {
let selector_parser = SelectorParser { let selector_parser = SelectorParser {
stylesheet_origin: self.context.stylesheet_origin, stylesheet_origin: self.context.stylesheet_origin,
namespaces: self.namespaces, namespaces: &self.context.namespaces,
url_data: self.context.url_data, url_data: self.context.url_data,
for_supports_rule: false, for_supports_rule: false,
}; };
@ -780,10 +740,9 @@ impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> {
start: &ParserState, start: &ParserState,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<CssRule, ParseError<'i>> { ) -> Result<CssRule, ParseError<'i>> {
let context = let declarations = self.nest_for_rule(CssRuleType::Style, |p| {
ParserContext::new_with_rule_type(self.context, CssRuleType::Style, self.namespaces); parse_property_declaration_list(&p.context, input, Some(&selectors))
});
let declarations = parse_property_declaration_list(&context, input, Some(&selectors));
let block = Arc::new(self.shared_lock.wrap(declarations)); let block = Arc::new(self.shared_lock.wrap(declarations));
Ok(CssRule::Style(Arc::new(self.shared_lock.wrap(StyleRule { Ok(CssRule::Style(Arc::new(self.shared_lock.wrap(StyleRule {
selectors, selectors,
@ -793,3 +752,14 @@ impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> {
})))) }))))
} }
} }
impl<'a, 'b, 'i> DeclarationParser<'i> for NestedRuleParser<'a, 'b> {
type Declaration = CssRule;
type Error = StyleParseErrorKind<'i>;
}
impl<'a, 'b, 'i> RuleBodyItemParser<'i, CssRule, StyleParseErrorKind<'i>> for NestedRuleParser<'a, 'b> {
fn parse_qualified(&self) -> bool { true }
// TODO: Nesting.
fn parse_declarations(&self) -> bool { false }
}

View file

@ -15,13 +15,12 @@ use crate::stylesheets::rules_iterator::{NestedRuleIterationCondition, RulesIter
use crate::stylesheets::{CssRule, CssRules, Origin, UrlExtraData}; use crate::stylesheets::{CssRule, CssRules, Origin, UrlExtraData};
use crate::use_counters::UseCounters; use crate::use_counters::UseCounters;
use crate::{Namespace, Prefix}; use crate::{Namespace, Prefix};
use cssparser::{Parser, ParserInput, RuleListParser}; use cssparser::{Parser, ParserInput, StyleSheetParser};
use fxhash::FxHashMap; use fxhash::FxHashMap;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf}; use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf};
use parking_lot::RwLock; use parking_lot::RwLock;
use servo_arc::Arc; use servo_arc::Arc;
use std::mem;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use style_traits::ParsingMode; use style_traits::ParsingMode;
@ -86,12 +85,10 @@ impl StylesheetContents {
allow_import_rules: AllowImportRules, allow_import_rules: AllowImportRules,
sanitization_data: Option<&mut SanitizationData>, sanitization_data: Option<&mut SanitizationData>,
) -> Arc<Self> { ) -> Arc<Self> {
let namespaces = RwLock::new(Namespaces::default()); let (namespaces, rules, source_map_url, source_url) = Stylesheet::parse_rules(
let (rules, source_map_url, source_url) = Stylesheet::parse_rules(
css, css,
&url_data, &url_data,
origin, origin,
&mut *namespaces.write(),
&shared_lock, &shared_lock,
stylesheet_loader, stylesheet_loader,
error_reporter, error_reporter,
@ -106,7 +103,7 @@ impl StylesheetContents {
rules: CssRules::new(rules, &shared_lock), rules: CssRules::new(rules, &shared_lock),
origin, origin,
url_data: RwLock::new(url_data), url_data: RwLock::new(url_data),
namespaces, namespaces: RwLock::new(namespaces),
quirks_mode, quirks_mode,
source_map_url: RwLock::new(source_map_url), source_map_url: RwLock::new(source_map_url),
source_url: RwLock::new(source_url), source_url: RwLock::new(source_url),
@ -426,14 +423,11 @@ impl Stylesheet {
line_number_offset: u32, line_number_offset: u32,
allow_import_rules: AllowImportRules, allow_import_rules: AllowImportRules,
) { ) {
let namespaces = RwLock::new(Namespaces::default());
// FIXME: Consider adding use counters to Servo? // FIXME: Consider adding use counters to Servo?
let (rules, source_map_url, source_url) = Self::parse_rules( let (namespaces, rules, source_map_url, source_url) = Self::parse_rules(
css, css,
&url_data, &url_data,
existing.contents.origin, existing.contents.origin,
&mut *namespaces.write(),
&existing.shared_lock, &existing.shared_lock,
stylesheet_loader, stylesheet_loader,
error_reporter, error_reporter,
@ -445,10 +439,7 @@ impl Stylesheet {
); );
*existing.contents.url_data.write() = url_data; *existing.contents.url_data.write() = url_data;
mem::swap( *existing.contents.namespaces.write() = namespaces;
&mut *existing.contents.namespaces.write(),
&mut *namespaces.write(),
);
// Acquire the lock *after* parsing, to minimize the exclusive section. // Acquire the lock *after* parsing, to minimize the exclusive section.
let mut guard = existing.shared_lock.write(); let mut guard = existing.shared_lock.write();
@ -461,7 +452,6 @@ impl Stylesheet {
css: &str, css: &str,
url_data: &UrlExtraData, url_data: &UrlExtraData,
origin: Origin, origin: Origin,
namespaces: &mut Namespaces,
shared_lock: &SharedRwLock, shared_lock: &SharedRwLock,
stylesheet_loader: Option<&dyn StylesheetLoader>, stylesheet_loader: Option<&dyn StylesheetLoader>,
error_reporter: Option<&dyn ParseErrorReporter>, error_reporter: Option<&dyn ParseErrorReporter>,
@ -470,7 +460,7 @@ impl Stylesheet {
use_counters: Option<&UseCounters>, use_counters: Option<&UseCounters>,
allow_import_rules: AllowImportRules, allow_import_rules: AllowImportRules,
mut sanitization_data: Option<&mut SanitizationData>, mut sanitization_data: Option<&mut SanitizationData>,
) -> (Vec<CssRule>, Option<String>, Option<String>) { ) -> (Namespaces, Vec<CssRule>, Option<String>, Option<String>) {
let mut rules = Vec::new(); let mut rules = Vec::new();
let mut input = ParserInput::new_with_line_number_offset(css, line_number_offset); let mut input = ParserInput::new_with_line_number_offset(css, line_number_offset);
let mut input = Parser::new(&mut input); let mut input = Parser::new(&mut input);
@ -481,23 +471,23 @@ impl Stylesheet {
None, None,
ParsingMode::DEFAULT, ParsingMode::DEFAULT,
quirks_mode, quirks_mode,
/* namespaces = */ Default::default(),
error_reporter, error_reporter,
use_counters, use_counters,
); );
let rule_parser = TopLevelRuleParser { let mut rule_parser = TopLevelRuleParser {
shared_lock, shared_lock,
loader: stylesheet_loader, loader: stylesheet_loader,
context, context,
state: State::Start, state: State::Start,
dom_error: None, dom_error: None,
insert_rule_context: None, insert_rule_context: None,
namespaces,
allow_import_rules, allow_import_rules,
}; };
{ {
let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser); let mut iter = StyleSheetParser::new(&mut input, &mut rule_parser);
loop { loop {
let result = match iter.next() { let result = match iter.next() {
@ -532,7 +522,7 @@ impl Stylesheet {
let source_map_url = input.current_source_map_url().map(String::from); let source_map_url = input.current_source_map_url().map(String::from);
let source_url = input.current_source_url().map(String::from); let source_url = input.current_source_url().map(String::from);
(rules, source_map_url, source_url) (rule_parser.context.namespaces.into_owned(), rules, source_map_url, source_url)
} }
/// Creates an empty stylesheet and parses it with a given base url, origin /// Creates an empty stylesheet and parses it with a given base url, origin

View file

@ -11,7 +11,7 @@ use crate::selector_parser::{SelectorImpl, SelectorParser};
use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked}; use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked};
use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
use crate::str::CssStringWriter; use crate::str::CssStringWriter;
use crate::stylesheets::{CssRuleType, CssRules, Namespaces}; use crate::stylesheets::{CssRuleType, CssRules};
use cssparser::parse_important; use cssparser::parse_important;
use cssparser::{Delimiter, Parser, SourceLocation, Token}; use cssparser::{Delimiter, Parser, SourceLocation, Token};
use cssparser::{ParseError as CssParseError, ParserInput}; use cssparser::{ParseError as CssParseError, ParserInput};
@ -228,15 +228,15 @@ impl SupportsCondition {
} }
/// Evaluate a supports condition /// Evaluate a supports condition
pub fn eval(&self, cx: &ParserContext, namespaces: &Namespaces) -> bool { pub fn eval(&self, cx: &ParserContext) -> bool {
match *self { match *self {
SupportsCondition::Not(ref cond) => !cond.eval(cx, namespaces), SupportsCondition::Not(ref cond) => !cond.eval(cx),
SupportsCondition::Parenthesized(ref cond) => cond.eval(cx, namespaces), SupportsCondition::Parenthesized(ref cond) => cond.eval(cx),
SupportsCondition::And(ref vec) => vec.iter().all(|c| c.eval(cx, namespaces)), SupportsCondition::And(ref vec) => vec.iter().all(|c| c.eval(cx)),
SupportsCondition::Or(ref vec) => vec.iter().any(|c| c.eval(cx, namespaces)), SupportsCondition::Or(ref vec) => vec.iter().any(|c| c.eval(cx)),
SupportsCondition::Declaration(ref decl) => decl.eval(cx), SupportsCondition::Declaration(ref decl) => decl.eval(cx),
SupportsCondition::MozBoolPref(ref name) => eval_moz_bool_pref(name, cx), SupportsCondition::MozBoolPref(ref name) => eval_moz_bool_pref(name, cx),
SupportsCondition::Selector(ref selector) => selector.eval(cx, namespaces), SupportsCondition::Selector(ref selector) => selector.eval(cx),
SupportsCondition::FontFormat(ref format) => eval_font_format(format), SupportsCondition::FontFormat(ref format) => eval_font_format(format),
SupportsCondition::FontTech(ref tech) => eval_font_tech(tech), SupportsCondition::FontTech(ref tech) => eval_font_tech(tech),
SupportsCondition::FutureSyntax(_) => false, SupportsCondition::FutureSyntax(_) => false,
@ -374,13 +374,13 @@ impl ToCss for RawSelector {
impl RawSelector { impl RawSelector {
/// Tries to evaluate a `selector()` function. /// Tries to evaluate a `selector()` function.
pub fn eval(&self, context: &ParserContext, namespaces: &Namespaces) -> bool { pub fn eval(&self, context: &ParserContext) -> bool {
let mut input = ParserInput::new(&self.0); let mut input = ParserInput::new(&self.0);
let mut input = Parser::new(&mut input); let mut input = Parser::new(&mut input);
input input
.parse_entirely(|input| -> Result<(), CssParseError<()>> { .parse_entirely(|input| -> Result<(), CssParseError<()>> {
let parser = SelectorParser { let parser = SelectorParser {
namespaces, namespaces: &context.namespaces,
stylesheet_origin: context.stylesheet_origin, stylesheet_origin: context.stylesheet_origin,
url_data: context.url_data, url_data: context.url_data,
for_supports_rule: true, for_supports_rule: true,

View file

@ -25,8 +25,8 @@ use crate::values::specified::{self, NoCalcLength};
use crate::values::specified::{NonNegativeLengthPercentageOrAuto, ViewportPercentageLength}; use crate::values::specified::{NonNegativeLengthPercentageOrAuto, ViewportPercentageLength};
use app_units::Au; use app_units::Au;
use cssparser::{ use cssparser::{
parse_important, AtRuleParser, CowRcStr, DeclarationListParser, DeclarationParser, Parser, parse_important, AtRuleParser, CowRcStr, DeclarationParser, Parser, QualifiedRuleParser,
QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser,
}; };
use euclid::Size2D; use euclid::Size2D;
use selectors::parser::SelectorParseErrorKind; use selectors::parser::SelectorParseErrorKind;
@ -233,15 +233,17 @@ fn parse_shorthand<'i, 't>(
} }
} }
type ViewportDeclarations = Vec<ViewportDescriptorDeclaration>;
impl<'a, 'b, 'i> AtRuleParser<'i> for ViewportRuleParser<'a, 'b> { impl<'a, 'b, 'i> AtRuleParser<'i> for ViewportRuleParser<'a, 'b> {
type Prelude = (); type Prelude = ();
type AtRule = Vec<ViewportDescriptorDeclaration>; type AtRule = ViewportDeclarations;
type Error = StyleParseErrorKind<'i>; type Error = StyleParseErrorKind<'i>;
} }
impl<'a, 'b, 'i> QualifiedRuleParser<'i> for ViewportRuleParser<'a, 'b> { impl<'a, 'b, 'i> QualifiedRuleParser<'i> for ViewportRuleParser<'a, 'b> {
type Prelude = (); type Prelude = ();
type QualifiedRule = Vec<ViewportDescriptorDeclaration>; type QualifiedRule = ViewportDeclarations;
type Error = StyleParseErrorKind<'i>; type Error = StyleParseErrorKind<'i>;
} }
@ -308,6 +310,11 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for ViewportRuleParser<'a, 'b> {
} }
} }
impl<'a, 'b, 'i> RuleBodyItemParser<'i, ViewportDeclarations, StyleParseErrorKind<'i>> for ViewportRuleParser<'a, 'b> {
fn parse_declarations(&self) -> bool { true }
fn parse_qualified(&self) -> bool { false }
}
/// A `@viewport` rule. /// A `@viewport` rule.
#[derive(Clone, Debug, PartialEq, ToShmem)] #[derive(Clone, Debug, PartialEq, ToShmem)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))] #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
@ -337,10 +344,10 @@ impl ViewportRule {
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
let parser = ViewportRuleParser { context }; let mut parser = ViewportRuleParser { context };
let mut cascade = Cascade::new(); let mut cascade = Cascade::new();
let mut parser = DeclarationListParser::new(input, parser); let mut parser = RuleBodyParser::new(input, &mut parser);
while let Some(result) = parser.next() { while let Some(result) = parser.next() {
match result { match result {
Ok(declarations) => { Ok(declarations) => {
@ -455,9 +462,7 @@ impl ViewportRule {
let declarations: Vec<_> = declarations.into_iter().filter_map(|entry| entry).collect(); let declarations: Vec<_> = declarations.into_iter().filter_map(|entry| entry).collect();
if !declarations.is_empty() { if !declarations.is_empty() {
Some(ViewportRule { Some(ViewportRule { declarations })
declarations: declarations,
})
} else { } else {
None None
} }
@ -784,8 +789,8 @@ impl MaybeNew for ViewportConstraints {
min_zoom: min_zoom.map(PinchZoomFactor::new), min_zoom: min_zoom.map(PinchZoomFactor::new),
max_zoom: max_zoom.map(PinchZoomFactor::new), max_zoom: max_zoom.map(PinchZoomFactor::new),
user_zoom: user_zoom, user_zoom,
orientation: orientation, orientation,
}) })
} }
} }

View file

@ -879,12 +879,7 @@ impl Parse for Attr {
/// Get the Namespace for a given prefix from the namespace map. /// Get the Namespace for a given prefix from the namespace map.
fn get_namespace_for_prefix(prefix: &Prefix, context: &ParserContext) -> Option<Namespace> { fn get_namespace_for_prefix(prefix: &Prefix, context: &ParserContext) -> Option<Namespace> {
context context.namespaces.prefixes.get(prefix).cloned()
.namespaces
.as_ref()?
.prefixes
.get(prefix)
.map(|x| x.clone())
} }
impl Attr { impl Attr {