diff --git a/components/script/dom/cssrulelist.rs b/components/script/dom/cssrulelist.rs index deb6b93e8b13..c10b9196092a 100644 --- a/components/script/dom/cssrulelist.rs +++ b/components/script/dom/cssrulelist.rs @@ -15,13 +15,23 @@ use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use parking_lot::RwLock; use std::sync::Arc; -use style::parser::ParserContextExtraData; -use style::stylesheets::{CssRules, KeyframesRule, Origin}; +use style::stylesheets::{CssRules, KeyframesRule, RulesMutateError}; use style::stylesheets::CssRule as StyleCssRule; no_jsmanaged_fields!(RulesSource); no_jsmanaged_fields!(CssRules); +impl From for Error { + fn from(other: RulesMutateError) -> Self { + match other { + RulesMutateError::Syntax => Error::Syntax, + RulesMutateError::IndexSize => Error::IndexSize, + RulesMutateError::HierarchyRequest => Error::HierarchyRequest, + RulesMutateError::InvalidState => Error::InvalidState, + } + } +} + #[dom_struct] pub struct CSSRuleList { reflector_: Reflector, @@ -64,21 +74,9 @@ impl CSSRuleList { CSSRuleListBinding::Wrap) } - /// https://drafts.csswg.org/cssom/#insert-a-css-rule - /// /// Should only be called for CssRules-backed rules. Use append_lazy_rule /// for keyframes-backed rules. pub fn insert_rule(&self, rule: &str, idx: u32, nested: bool) -> Fallible { - use style::stylesheets::SingleRuleParseError; - /// Insert an item into a vector, appending if it is out of bounds - fn insert(vec: &mut Vec, index: usize, item: T) { - if index >= vec.len() { - vec.push(item); - } else { - vec.insert(index, item); - } - } - let css_rules = if let RulesSource::Rules(ref rules) = self.rules { rules } else { @@ -90,58 +88,12 @@ impl CSSRuleList { let doc = window.Document(); let index = idx as usize; + let new_rule = css_rules.insert_rule(rule, doc.url().clone(), index, nested)?; - let new_rule = { - let rules = css_rules.0.read(); - let state = if nested { - None - } else { - Some(CssRules::state_at_index(&rules, index)) - }; - - let rev_state = CssRules::state_at_index_rev(&rules, index); - - // Step 1, 2 - // XXXManishearth get url from correct location - // XXXManishearth should we also store the namespace map? - let parse_result = StyleCssRule::parse(&rule, Origin::Author, - doc.url().clone(), - ParserContextExtraData::default(), - state); - - if let Err(SingleRuleParseError::Syntax) = parse_result { - return Err(Error::Syntax) - } - - // Step 3, 4 - if index > rules.len() { - return Err(Error::IndexSize); - } - - let (new_rule, new_state) = try!(parse_result.map_err(|_| Error::HierarchyRequest)); - - if new_state > rev_state { - // We inserted a rule too early, e.g. inserting - // a regular style rule before @namespace rules - return Err((Error::HierarchyRequest)); - } - - // Step 6 - if let StyleCssRule::Namespace(..) = new_rule { - if !CssRules::only_ns_or_import(&rules) { - return Err(Error::InvalidState); - } - } - - new_rule - }; - - insert(&mut css_rules.0.write(), index, new_rule.clone()); let sheet = self.sheet.get(); let sheet = sheet.as_ref().map(|sheet| &**sheet); let dom_rule = CSSRule::new_specific(&window, sheet, new_rule); - insert(&mut self.dom_rules.borrow_mut(), - index, MutNullableHeap::new(Some(&*dom_rule))); + self.dom_rules.borrow_mut().insert(index, MutNullableHeap::new(Some(&*dom_rule))); Ok((idx)) } diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 12ca0423cfa5..cce7e40c223d 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -60,6 +60,22 @@ impl From> for CssRules { } } +pub enum RulesMutateError { + Syntax, + IndexSize, + HierarchyRequest, + InvalidState, +} + +impl From for RulesMutateError { + fn from(other: SingleRuleParseError) -> Self { + match other { + SingleRuleParseError::Syntax => RulesMutateError::Syntax, + SingleRuleParseError::Hierarchy => RulesMutateError::HierarchyRequest, + } + } +} + impl CssRules { // used in CSSOM pub fn only_ns_or_import(rules: &[CssRule]) -> bool { @@ -102,6 +118,46 @@ impl CssRules { State::Body } } + + /// https://drafts.csswg.org/cssom/#insert-a-css-rule + pub fn insert_rule(&self, rule: &str, base_url: ServoUrl, index: usize, nested: bool) + -> Result { + let mut rules = self.0.write(); + + // Step 1, 2 + if index > rules.len() { + return Err(RulesMutateError::IndexSize); + } + + let state = if nested { + None + } else { + Some(CssRules::state_at_index(&rules, index)) + }; + + // Step 3, 4 + // XXXManishearth should we also store the namespace map? + let (new_rule, new_state) = try!(CssRule::parse(&rule, Origin::Author, base_url, + ParserContextExtraData::default(), state)); + + // Step 5 + let rev_state = CssRules::state_at_index_rev(&rules, index); + if new_state > rev_state { + // We inserted a rule too early, e.g. inserting + // a regular style rule before @namespace rules + return Err(RulesMutateError::HierarchyRequest); + } + + // Step 6 + if let CssRule::Namespace(..) = new_rule { + if !CssRules::only_ns_or_import(&rules) { + return Err(RulesMutateError::InvalidState); + } + } + + rules.insert(index, new_rule.clone()); + Ok(new_rule) + } } #[derive(Debug)]