diff options
author | Emilio Cobos Álvarez <emilio@crisal.io> | 2017-06-02 13:40:26 +0200 |
---|---|---|
committer | Emilio Cobos Álvarez <emilio@crisal.io> | 2017-06-02 14:38:05 +0200 |
commit | bbd85ccbda2ced5994205a4362cca92b7e4837ab (patch) | |
tree | 0262b3542c7972820eb11430b2fe118b00d33ab0 | |
parent | 26ef0f6178341d7155ac0d3bb2654f2f613bdee1 (diff) | |
download | servo-bbd85ccbda2ced5994205a4362cca92b7e4837ab.tar.gz servo-bbd85ccbda2ced5994205a4362cca92b7e4837ab.zip |
style: Simplify the namespace setup for stylesheet parsing.
-rw-r--r-- | components/style/parser.rs | 40 | ||||
-rw-r--r-- | components/style/stylesheets.rs | 170 | ||||
-rw-r--r-- | components/style/values/specified/mod.rs | 24 |
3 files changed, 156 insertions, 78 deletions
diff --git a/components/style/parser.rs b/components/style/parser.rs index cad388651f9..162c690c87c 100644 --- a/components/style/parser.rs +++ b/components/style/parser.rs @@ -7,7 +7,6 @@ use context::QuirksMode; use cssparser::{Parser, SourcePosition, UnicodeRange}; use error_reporting::ParseErrorReporter; -use parking_lot::RwLock; use style_traits::OneOrMoreCommaSeparated; use stylesheets::{CssRuleType, Origin, UrlExtraData, Namespaces}; @@ -82,8 +81,8 @@ pub struct ParserContext<'a> { pub parsing_mode: ParsingMode, /// The quirks mode of this stylesheet. pub quirks_mode: QuirksMode, - /// The list of all namespaces active in the current stylesheet - pub namespaces: Option<&'a RwLock<Namespaces>>, + /// The currently active namespaces. + pub namespaces: Option<&'a Namespaces>, } impl<'a> ParserContext<'a> { @@ -108,19 +107,21 @@ impl<'a> ParserContext<'a> { } /// Create a parser context for on-the-fly parsing in CSSOM - pub fn new_for_cssom(url_data: &'a UrlExtraData, - error_reporter: &'a ParseErrorReporter, - rule_type: Option<CssRuleType>, - parsing_mode: ParsingMode, - quirks_mode: QuirksMode) - -> ParserContext<'a> { + pub fn new_for_cssom( + url_data: &'a UrlExtraData, + error_reporter: &'a ParseErrorReporter, + rule_type: Option<CssRuleType>, + parsing_mode: ParsingMode, + quirks_mode: QuirksMode + ) -> ParserContext<'a> { Self::new(Origin::Author, url_data, error_reporter, rule_type, parsing_mode, quirks_mode) } /// Create a parser context based on a previous context, but with a modified rule type. - pub fn new_with_rule_type(context: &'a ParserContext, - rule_type: Option<CssRuleType>) - -> ParserContext<'a> { + pub fn new_with_rule_type( + context: &'a ParserContext, + rule_type: Option<CssRuleType> + ) -> ParserContext<'a> { ParserContext { stylesheet_origin: context.stylesheet_origin, url_data: context.url_data, @@ -134,13 +135,14 @@ impl<'a> ParserContext<'a> { } /// Create a parser context for inline CSS which accepts additional line offset argument. - pub fn new_with_line_number_offset(stylesheet_origin: Origin, - url_data: &'a UrlExtraData, - error_reporter: &'a ParseErrorReporter, - line_number_offset: u64, - parsing_mode: ParsingMode, - quirks_mode: QuirksMode) - -> ParserContext<'a> { + pub fn new_with_line_number_offset( + stylesheet_origin: Origin, + url_data: &'a UrlExtraData, + error_reporter: &'a ParseErrorReporter, + line_number_offset: u64, + parsing_mode: ParsingMode, + quirks_mode: QuirksMode + ) -> ParserContext<'a> { ParserContext { stylesheet_origin: stylesheet_origin, url_data: url_data, diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 1f3345b0810..6347e39f0e9 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -478,15 +478,19 @@ impl CssRule { loader: Option<&StylesheetLoader>) -> Result<(Self, State), SingleRuleParseError> { let error_reporter = NullReporter; - let mut context = ParserContext::new(parent_stylesheet.origin, - &parent_stylesheet.url_data, - &error_reporter, - None, - PARSING_MODE_DEFAULT, - parent_stylesheet.quirks_mode); - context.namespaces = Some(&parent_stylesheet.namespaces); + let context = ParserContext::new( + parent_stylesheet.origin, + &parent_stylesheet.url_data, + &error_reporter, + None, + PARSING_MODE_DEFAULT, + parent_stylesheet.quirks_mode + ); + let mut input = Parser::new(css); + let mut guard = parent_stylesheet.namespaces.write(); + // nested rules are in the body state let state = state.unwrap_or(State::Body); let mut rule_parser = TopLevelRuleParser { @@ -495,6 +499,7 @@ impl CssRule { shared_lock: &parent_stylesheet.shared_lock, loader: loader, state: state, + namespaces: Some(&mut *guard), }; match parse_one_rule(&mut input, &mut rule_parser) { Ok(result) => Ok((result, rule_parser.state)), @@ -509,8 +514,10 @@ impl CssRule { } /// Deep clones this CssRule. - fn deep_clone_with_lock(&self, - lock: &SharedRwLock) -> CssRule { + fn deep_clone_with_lock( + &self, + lock: &SharedRwLock + ) -> CssRule { let guard = lock.read(); match *self { CssRule::Namespace(ref arc) => { @@ -1214,10 +1221,19 @@ impl Stylesheet { let namespaces = RwLock::new(Namespaces::default()); // FIXME: we really should update existing.url_data with the given url_data, // otherwise newly inserted rule may not have the right base url. - let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules( - css, url_data, existing.origin, &namespaces, - &existing.shared_lock, stylesheet_loader, error_reporter, - existing.quirks_mode, line_number_offset); + let (rules, dirty_on_viewport_size_change) = + Stylesheet::parse_rules( + css, + url_data, + existing.origin, + &mut *namespaces.write(), + &existing.shared_lock, + stylesheet_loader, + error_reporter, + existing.quirks_mode, + line_number_offset + ); + mem::swap(&mut *existing.namespaces.write(), &mut *namespaces.write()); existing.dirty_on_viewport_size_change .store(dirty_on_viewport_size_change, Ordering::Release); @@ -1227,35 +1243,45 @@ impl Stylesheet { *existing.rules.write_with(&mut guard) = CssRules(rules); } - fn parse_rules(css: &str, - url_data: &UrlExtraData, - origin: Origin, - namespaces: &RwLock<Namespaces>, - shared_lock: &SharedRwLock, - stylesheet_loader: Option<&StylesheetLoader>, - error_reporter: &ParseErrorReporter, - quirks_mode: QuirksMode, - line_number_offset: u64) - -> (Vec<CssRule>, bool) { + fn parse_rules( + css: &str, + url_data: &UrlExtraData, + origin: Origin, + namespaces: &mut Namespaces, + shared_lock: &SharedRwLock, + stylesheet_loader: Option<&StylesheetLoader>, + error_reporter: &ParseErrorReporter, + quirks_mode: QuirksMode, + line_number_offset: u64 + ) -> (Vec<CssRule>, bool) { let mut rules = Vec::new(); let mut input = Parser::new(css); - let mut context = ParserContext::new_with_line_number_offset(origin, url_data, error_reporter, - line_number_offset, - PARSING_MODE_DEFAULT, - quirks_mode); - context.namespaces = Some(namespaces); + + let context = + ParserContext::new_with_line_number_offset( + origin, + url_data, + error_reporter, + line_number_offset, + PARSING_MODE_DEFAULT, + quirks_mode + ); + let rule_parser = TopLevelRuleParser { stylesheet_origin: origin, shared_lock: shared_lock, loader: stylesheet_loader, context: context, state: State::Start, + namespaces: Some(namespaces), }; input.look_for_viewport_percentages(); { - let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser); + let mut iter = + RuleListParser::new_for_stylesheet(&mut input, rule_parser); + while let Some(result) = iter.next() { match result { Ok(rule) => rules.push(rule), @@ -1288,9 +1314,17 @@ impl Stylesheet { -> Stylesheet { let namespaces = RwLock::new(Namespaces::default()); let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules( - css, &url_data, origin, &namespaces, - &shared_lock, stylesheet_loader, error_reporter, quirks_mode, line_number_offset, + css, + &url_data, + origin, + &mut *namespaces.write(), + &shared_lock, + stylesheet_loader, + error_reporter, + quirks_mode, + line_number_offset, ); + Stylesheet { origin: origin, url_data: url_data, @@ -1477,6 +1511,7 @@ struct TopLevelRuleParser<'a> { loader: Option<&'a StylesheetLoader>, context: ParserContext<'a>, state: State, + namespaces: Option<&'a mut Namespaces>, } impl<'b> TopLevelRuleParser<'b> { @@ -1548,8 +1583,11 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { type Prelude = AtRulePrelude; type AtRule = CssRule; - fn parse_prelude(&mut self, name: &str, input: &mut Parser) - -> Result<AtRuleType<AtRulePrelude, CssRule>, ()> { + fn parse_prelude( + &mut self, + name: &str, + input: &mut Parser + ) -> Result<AtRuleType<AtRulePrelude, CssRule>, ()> { let location = get_location_with_offset(input.current_source_location(), self.context.line_number_offset); match_ignore_ascii_case! { name, @@ -1608,14 +1646,16 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { let id = register_namespace(&url)?; + let mut namespaces = self.namespaces.as_mut().unwrap(); + let opt_prefix = if let Ok(prefix) = prefix_result { let prefix = Prefix::from(prefix); - self.context.namespaces.expect("namespaces must be set whilst parsing rules") - .write().prefixes.insert(prefix.clone(), (url.clone(), id)); + namespaces + .prefixes + .insert(prefix.clone(), (url.clone(), id)); Some(prefix) } else { - self.context.namespaces.expect("namespaces must be set whilst parsing rules") - .write().default = Some((url.clone(), id)); + namespaces.default = Some((url.clone(), id)); None }; @@ -1638,6 +1678,13 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> { return Err(()); } self.state = State::Body; + + // "Freeze" the namespace map (no more namespace rules can be parsed + // after this point), and stick it in the context. + if self.namespaces.is_some() { + let namespaces = &*self.namespaces.take().unwrap(); + self.context.namespaces = Some(namespaces); + } AtRuleParser::parse_prelude(&mut self.nested(), name, input) } @@ -1655,12 +1702,23 @@ impl<'a> QualifiedRuleParser for TopLevelRuleParser<'a> { #[inline] fn parse_prelude(&mut self, input: &mut Parser) -> Result<SelectorList<SelectorImpl>, ()> { self.state = State::Body; + + // "Freeze" the namespace map (no more namespace rules can be parsed + // after this point), and stick it in the context. + if self.namespaces.is_some() { + let namespaces = &*self.namespaces.take().unwrap(); + self.context.namespaces = Some(namespaces); + } + QualifiedRuleParser::parse_prelude(&mut self.nested(), input) } #[inline] - fn parse_block(&mut self, prelude: SelectorList<SelectorImpl>, input: &mut Parser) - -> Result<CssRule, ()> { + fn parse_block( + &mut self, + prelude: SelectorList<SelectorImpl>, + input: &mut Parser + ) -> Result<CssRule, ()> { QualifiedRuleParser::parse_block(&mut self.nested(), prelude, input) } } @@ -1673,13 +1731,19 @@ struct NestedRuleParser<'a, 'b: 'a> { } impl<'a, 'b> NestedRuleParser<'a, 'b> { - fn parse_nested_rules(&self, input: &mut Parser, rule_type: CssRuleType) -> Arc<Locked<CssRules>> { + fn parse_nested_rules( + &mut self, + input: &mut Parser, + rule_type: CssRuleType + ) -> Arc<Locked<CssRules>> { let context = ParserContext::new_with_rule_type(self.context, Some(rule_type)); + let nested_parser = NestedRuleParser { stylesheet_origin: self.stylesheet_origin, shared_lock: self.shared_lock, context: &context, }; + let mut iter = RuleListParser::new_for_nested_rule(input, nested_parser); let mut rules = Vec::new(); while let Some(result) = iter.next() { @@ -1710,10 +1774,17 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { type Prelude = AtRulePrelude; type AtRule = CssRule; - fn parse_prelude(&mut self, name: &str, input: &mut Parser) - -> Result<AtRuleType<AtRulePrelude, CssRule>, ()> { - let location = get_location_with_offset(input.current_source_location(), - self.context.line_number_offset); + fn parse_prelude( + &mut self, + name: &str, + input: &mut Parser + ) -> Result<AtRuleType<AtRulePrelude, CssRule>, ()> { + let location = + get_location_with_offset( + input.current_source_location(), + self.context.line_number_offset + ); + match_ignore_ascii_case! { name, "media" => { let media_queries = parse_media_query_list(self.context, input); @@ -1854,16 +1925,19 @@ impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> { type QualifiedRule = CssRule; fn parse_prelude(&mut self, input: &mut Parser) -> Result<SelectorList<SelectorImpl>, ()> { - let ns = self.context.namespaces.expect("namespaces must be set when parsing rules").read(); let selector_parser = SelectorParser { stylesheet_origin: self.stylesheet_origin, - namespaces: &*ns, + namespaces: self.context.namespaces.unwrap(), }; + SelectorList::parse(&selector_parser, input) } - fn parse_block(&mut self, prelude: SelectorList<SelectorImpl>, input: &mut Parser) - -> Result<CssRule, ()> { + fn parse_block( + &mut self, + prelude: SelectorList<SelectorImpl>, + input: &mut Parser + ) -> Result<CssRule, ()> { let location = get_location_with_offset(input.current_source_location(), self.context.line_number_offset); let context = ParserContext::new_with_rule_type(self.context, Some(CssRuleType::Style)); diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 0131bdb5f28..877040bfd33 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -1396,23 +1396,25 @@ impl Parse for Attr { #[cfg(feature = "gecko")] /// Get the namespace id from the namespace map -pub fn get_id_for_namespace(namespace: &Namespace, context: &ParserContext) -> Result<NamespaceId, ()> { - if let Some(map) = context.namespaces { - if let Some(ref entry) = map.read().prefixes.get(&namespace.0) { - Ok(entry.1) - } else { - Err(()) +fn get_id_for_namespace(namespace: &Namespace, context: &ParserContext) -> Result<NamespaceId, ()> { + let namespaces_map = match context.namespaces { + Some(map) => map, + None => { + // If we don't have a namespace map (e.g. in inline styles) + // we can't parse namespaces + return Err(()); } - } else { - // if we don't have a namespace map (e.g. in inline styles) - // we can't parse namespaces - Err(()) + }; + + match namespaces_map.prefixes.get(&namespace.0) { + Some(entry) => Ok(entry.1), + None => Err(()), } } #[cfg(feature = "servo")] /// Get the namespace id from the namespace map -pub fn get_id_for_namespace(_: &Namespace, _: &ParserContext) -> Result<NamespaceId, ()> { +fn get_id_for_namespace(_: &Namespace, _: &ParserContext) -> Result<NamespaceId, ()> { Ok(()) } |