diff options
Diffstat (limited to 'components/script/dom')
22 files changed, 499 insertions, 57 deletions
diff --git a/components/script/dom/cssfontfacerule.rs b/components/script/dom/cssfontfacerule.rs index 18371c89c45..60022b7ba8f 100644 --- a/components/script/dom/cssfontfacerule.rs +++ b/components/script/dom/cssfontfacerule.rs @@ -22,7 +22,7 @@ pub struct CSSFontFaceRule { } impl CSSFontFaceRule { - fn new_inherited(parent: &CSSStyleSheet, fontfacerule: Arc<RwLock<FontFaceRule>>) -> CSSFontFaceRule { + fn new_inherited(parent: Option<&CSSStyleSheet>, fontfacerule: Arc<RwLock<FontFaceRule>>) -> CSSFontFaceRule { CSSFontFaceRule { cssrule: CSSRule::new_inherited(parent), fontfacerule: fontfacerule, @@ -30,7 +30,7 @@ impl CSSFontFaceRule { } #[allow(unrooted_must_root)] - pub fn new(window: &Window, parent: &CSSStyleSheet, + pub fn new(window: &Window, parent: Option<&CSSStyleSheet>, fontfacerule: Arc<RwLock<FontFaceRule>>) -> Root<CSSFontFaceRule> { reflect_dom_object(box CSSFontFaceRule::new_inherited(parent, fontfacerule), window, diff --git a/components/script/dom/cssgroupingrule.rs b/components/script/dom/cssgroupingrule.rs index 3558686ea74..cd55cd358b6 100644 --- a/components/script/dom/cssgroupingrule.rs +++ b/components/script/dom/cssgroupingrule.rs @@ -3,28 +3,67 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::Bindings::CSSGroupingRuleBinding; -use dom::bindings::js::Root; -use dom::bindings::reflector::reflect_dom_object; +use dom::bindings::codegen::Bindings::CSSGroupingRuleBinding::CSSGroupingRuleMethods; +use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleBinding::CSSRuleMethods; +use dom::bindings::error::{ErrorResult, Fallible}; +use dom::bindings::inheritance::Castable; +use dom::bindings::js::{JS, MutNullableHeap, Root}; +use dom::bindings::reflector::{Reflectable, reflect_dom_object}; +use dom::bindings::str::DOMString; use dom::cssrule::CSSRule; +use dom::cssrulelist::{CSSRuleList, RulesSource}; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; +use style::stylesheets::CssRules as StyleCssRules; #[dom_struct] pub struct CSSGroupingRule { cssrule: CSSRule, + #[ignore_heap_size_of = "Arc"] + rules: StyleCssRules, + rulelist: MutNullableHeap<JS<CSSRuleList>>, } impl CSSGroupingRule { - pub fn new_inherited(parent: &CSSStyleSheet) -> CSSGroupingRule { + pub fn new_inherited(parent: Option<&CSSStyleSheet>, + rules: StyleCssRules) -> CSSGroupingRule { CSSGroupingRule { cssrule: CSSRule::new_inherited(parent), + rules: rules, + rulelist: MutNullableHeap::new(None), } } #[allow(unrooted_must_root)] - pub fn new(window: &Window, parent: &CSSStyleSheet) -> Root<CSSGroupingRule> { - reflect_dom_object(box CSSGroupingRule::new_inherited(parent), + pub fn new(window: &Window, parent: Option<&CSSStyleSheet>, rules: StyleCssRules) -> Root<CSSGroupingRule> { + reflect_dom_object(box CSSGroupingRule::new_inherited(parent, rules), window, CSSGroupingRuleBinding::Wrap) } + + fn rulelist(&self) -> Root<CSSRuleList> { + let sheet = self.upcast::<CSSRule>().GetParentStyleSheet(); + let sheet = sheet.as_ref().map(|s| &**s); + self.rulelist.or_init(|| CSSRuleList::new(self.global().as_window(), + sheet, + RulesSource::Rules(self.rules.clone()))) + } +} + +impl CSSGroupingRuleMethods for CSSGroupingRule { + // https://drafts.csswg.org/cssom/#dom-cssgroupingrule-cssrules + fn CssRules(&self) -> Root<CSSRuleList> { + // XXXManishearth check origin clean flag + self.rulelist() + } + + // https://drafts.csswg.org/cssom/#dom-cssgroupingrule-insertrule + fn InsertRule(&self, rule: DOMString, index: u32) -> Fallible<u32> { + self.rulelist().insert_rule(&rule, index, /* nested */ true) + } + + // https://drafts.csswg.org/cssom/#dom-cssgroupingrule-deleterule + fn DeleteRule(&self, index: u32) -> ErrorResult { + self.rulelist().remove_rule(index) + } } diff --git a/components/script/dom/csskeyframerule.rs b/components/script/dom/csskeyframerule.rs new file mode 100644 index 00000000000..e09099e1135 --- /dev/null +++ b/components/script/dom/csskeyframerule.rs @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use dom::bindings::codegen::Bindings::CSSKeyframeRuleBinding; +use dom::bindings::js::Root; +use dom::bindings::reflector::reflect_dom_object; +use dom::bindings::str::DOMString; +use dom::cssrule::{CSSRule, SpecificCSSRule}; +use dom::cssstylesheet::CSSStyleSheet; +use dom::window::Window; +use parking_lot::RwLock; +use std::sync::Arc; +use style::keyframes::Keyframe; +use style_traits::ToCss; + +#[dom_struct] +pub struct CSSKeyframeRule { + cssrule: CSSRule, + #[ignore_heap_size_of = "Arc"] + keyframerule: Arc<RwLock<Keyframe>>, +} + +impl CSSKeyframeRule { + fn new_inherited(parent: Option<&CSSStyleSheet>, keyframerule: Arc<RwLock<Keyframe>>) -> CSSKeyframeRule { + CSSKeyframeRule { + cssrule: CSSRule::new_inherited(parent), + keyframerule: keyframerule, + } + } + + #[allow(unrooted_must_root)] + pub fn new(window: &Window, parent: Option<&CSSStyleSheet>, + keyframerule: Arc<RwLock<Keyframe>>) -> Root<CSSKeyframeRule> { + reflect_dom_object(box CSSKeyframeRule::new_inherited(parent, keyframerule), + window, + CSSKeyframeRuleBinding::Wrap) + } +} + +impl SpecificCSSRule for CSSKeyframeRule { + fn ty(&self) -> u16 { + use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants; + CSSRuleConstants::KEYFRAME_RULE + } + + fn get_css(&self) -> DOMString { + self.keyframerule.read().to_css_string().into() + } +} diff --git a/components/script/dom/csskeyframesrule.rs b/components/script/dom/csskeyframesrule.rs index 138c8b20558..b7baf6b85a9 100644 --- a/components/script/dom/csskeyframesrule.rs +++ b/components/script/dom/csskeyframesrule.rs @@ -2,16 +2,25 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use cssparser::Parser; use dom::bindings::codegen::Bindings::CSSKeyframesRuleBinding; -use dom::bindings::js::Root; -use dom::bindings::reflector::reflect_dom_object; +use dom::bindings::codegen::Bindings::CSSKeyframesRuleBinding::CSSKeyframesRuleMethods; +use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleMethods; +use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; +use dom::bindings::inheritance::Castable; +use dom::bindings::js::{JS, MutNullableHeap, Root}; +use dom::bindings::reflector::{Reflectable, reflect_dom_object}; use dom::bindings::str::DOMString; +use dom::csskeyframerule::CSSKeyframeRule; use dom::cssrule::{CSSRule, SpecificCSSRule}; +use dom::cssrulelist::{CSSRuleList, RulesSource}; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; use parking_lot::RwLock; use std::sync::Arc; -use style::stylesheets::KeyframesRule; +use style::keyframes::{Keyframe, KeyframeSelector}; +use style::parser::ParserContextExtraData; +use style::stylesheets::{KeyframesRule, Origin}; use style_traits::ToCss; #[dom_struct] @@ -19,23 +28,84 @@ pub struct CSSKeyframesRule { cssrule: CSSRule, #[ignore_heap_size_of = "Arc"] keyframesrule: Arc<RwLock<KeyframesRule>>, + rulelist: MutNullableHeap<JS<CSSRuleList>>, } impl CSSKeyframesRule { - fn new_inherited(parent: &CSSStyleSheet, keyframesrule: Arc<RwLock<KeyframesRule>>) -> CSSKeyframesRule { + fn new_inherited(parent: Option<&CSSStyleSheet>, keyframesrule: Arc<RwLock<KeyframesRule>>) -> CSSKeyframesRule { CSSKeyframesRule { cssrule: CSSRule::new_inherited(parent), keyframesrule: keyframesrule, + rulelist: MutNullableHeap::new(None), } } #[allow(unrooted_must_root)] - pub fn new(window: &Window, parent: &CSSStyleSheet, + pub fn new(window: &Window, parent: Option<&CSSStyleSheet>, keyframesrule: Arc<RwLock<KeyframesRule>>) -> Root<CSSKeyframesRule> { reflect_dom_object(box CSSKeyframesRule::new_inherited(parent, keyframesrule), window, CSSKeyframesRuleBinding::Wrap) } + + fn rulelist(&self) -> Root<CSSRuleList> { + self.rulelist.or_init(|| { + let sheet = self.upcast::<CSSRule>().GetParentStyleSheet(); + let sheet = sheet.as_ref().map(|s| &**s); + CSSRuleList::new(self.global().as_window(), + sheet, + RulesSource::Keyframes(self.keyframesrule.clone())) + }) + } + + /// Given a keyframe selector, finds the index of the first corresponding rule if any + fn find_rule(&self, selector: &str) -> Option<usize> { + let mut input = Parser::new(selector); + if let Ok(sel) = KeyframeSelector::parse(&mut input) { + // This finds the *last* element matching a selector + // because that's the rule that applies. Thus, rposition + self.keyframesrule.read() + .keyframes.iter().rposition(|frame| { + frame.read().selector == sel + }) + } else { + None + } + } +} + +impl CSSKeyframesRuleMethods for CSSKeyframesRule { + // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-cssrules + fn CssRules(&self) -> Root<CSSRuleList> { + self.rulelist() + } + + // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-appendrule + fn AppendRule(&self, rule: DOMString) { + let global = self.global(); + let window = global.as_window(); + let doc = window.Document(); + let rule = Keyframe::parse(&rule, Origin::Author, doc.url().clone(), + ParserContextExtraData::default()); + if let Ok(rule) = rule { + self.keyframesrule.write().keyframes.push(rule); + self.rulelist().append_lazy_dom_rule(); + } + } + + // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-deleterule + fn DeleteRule(&self, selector: DOMString) { + if let Some(idx) = self.find_rule(&selector) { + let _ = self.rulelist().remove_rule(idx as u32); + } + } + + // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-findrule + fn FindRule(&self, selector: DOMString) -> Option<Root<CSSKeyframeRule>> { + self.find_rule(&selector).and_then(|idx| { + self.rulelist().item(idx as u32) + }).and_then(Root::downcast) + } } impl SpecificCSSRule for CSSKeyframesRule { @@ -47,4 +117,8 @@ impl SpecificCSSRule for CSSKeyframesRule { fn get_css(&self) -> DOMString { self.keyframesrule.read().to_css_string().into() } + + fn deparent_children(&self) { + self.rulelist.get().map(|list| list.deparent_all()); + } } diff --git a/components/script/dom/cssmediarule.rs b/components/script/dom/cssmediarule.rs index a8d8649b31f..67933fccd3b 100644 --- a/components/script/dom/cssmediarule.rs +++ b/components/script/dom/cssmediarule.rs @@ -23,15 +23,16 @@ pub struct CSSMediaRule { } impl CSSMediaRule { - fn new_inherited(parent: &CSSStyleSheet, mediarule: Arc<RwLock<MediaRule>>) -> CSSMediaRule { + fn new_inherited(parent: Option<&CSSStyleSheet>, mediarule: Arc<RwLock<MediaRule>>) -> CSSMediaRule { + let list = mediarule.read().rules.clone(); CSSMediaRule { - cssrule: CSSGroupingRule::new_inherited(parent), + cssrule: CSSGroupingRule::new_inherited(parent, list), mediarule: mediarule, } } #[allow(unrooted_must_root)] - pub fn new(window: &Window, parent: &CSSStyleSheet, + pub fn new(window: &Window, parent: Option<&CSSStyleSheet>, mediarule: Arc<RwLock<MediaRule>>) -> Root<CSSMediaRule> { reflect_dom_object(box CSSMediaRule::new_inherited(parent, mediarule), window, diff --git a/components/script/dom/cssnamespacerule.rs b/components/script/dom/cssnamespacerule.rs index 04c4431df77..4e93eea2e1f 100644 --- a/components/script/dom/cssnamespacerule.rs +++ b/components/script/dom/cssnamespacerule.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::Bindings::CSSNamespaceRuleBinding; +use dom::bindings::codegen::Bindings::CSSNamespaceRuleBinding::CSSNamespaceRuleMethods; use dom::bindings::js::Root; use dom::bindings::reflector::reflect_dom_object; use dom::bindings::str::DOMString; @@ -22,7 +23,7 @@ pub struct CSSNamespaceRule { } impl CSSNamespaceRule { - fn new_inherited(parent: &CSSStyleSheet, namespacerule: Arc<RwLock<NamespaceRule>>) -> CSSNamespaceRule { + fn new_inherited(parent: Option<&CSSStyleSheet>, namespacerule: Arc<RwLock<NamespaceRule>>) -> CSSNamespaceRule { CSSNamespaceRule { cssrule: CSSRule::new_inherited(parent), namespacerule: namespacerule, @@ -30,7 +31,7 @@ impl CSSNamespaceRule { } #[allow(unrooted_must_root)] - pub fn new(window: &Window, parent: &CSSStyleSheet, + pub fn new(window: &Window, parent: Option<&CSSStyleSheet>, namespacerule: Arc<RwLock<NamespaceRule>>) -> Root<CSSNamespaceRule> { reflect_dom_object(box CSSNamespaceRule::new_inherited(parent, namespacerule), window, @@ -38,6 +39,20 @@ impl CSSNamespaceRule { } } +impl CSSNamespaceRuleMethods for CSSNamespaceRule { + // https://drafts.csswg.org/cssom/#dom-cssnamespacerule-prefix + fn Prefix(&self) -> DOMString { + self.namespacerule.read().prefix + .as_ref().map(|s| s.to_string().into()) + .unwrap_or(DOMString::new()) + } + + // https://drafts.csswg.org/cssom/#dom-cssnamespacerule-namespaceuri + fn NamespaceURI(&self) -> DOMString { + (*self.namespacerule.read().url).into() + } +} + impl SpecificCSSRule for CSSNamespaceRule { fn ty(&self) -> u16 { use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants; diff --git a/components/script/dom/cssrule.rs b/components/script/dom/cssrule.rs index e46738bb1b4..ca1e52b77f0 100644 --- a/components/script/dom/cssrule.rs +++ b/components/script/dom/cssrule.rs @@ -9,6 +9,7 @@ use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::bindings::str::DOMString; use dom::cssfontfacerule::CSSFontFaceRule; +use dom::csskeyframerule::CSSKeyframeRule; use dom::csskeyframesrule::CSSKeyframesRule; use dom::cssmediarule::CSSMediaRule; use dom::cssnamespacerule::CSSNamespaceRule; @@ -27,15 +28,15 @@ pub struct CSSRule { impl CSSRule { #[allow(unrooted_must_root)] - pub fn new_inherited(parent: &CSSStyleSheet) -> CSSRule { + pub fn new_inherited(parent: Option<&CSSStyleSheet>) -> CSSRule { CSSRule { reflector_: Reflector::new(), - parent: MutNullableHeap::new(Some(parent)), + parent: MutNullableHeap::new(parent), } } #[allow(unrooted_must_root)] - pub fn new(window: &Window, parent: &CSSStyleSheet) -> Root<CSSRule> { + pub fn new(window: &Window, parent: Option<&CSSStyleSheet>) -> Root<CSSRule> { reflect_dom_object(box CSSRule::new_inherited(parent), window, CSSRuleBinding::Wrap) @@ -54,6 +55,8 @@ impl CSSRule { rule as &SpecificCSSRule } else if let Some(rule) = self.downcast::<CSSViewportRule>() { rule as &SpecificCSSRule + } else if let Some(rule) = self.downcast::<CSSKeyframeRule>() { + rule as &SpecificCSSRule } else { unreachable!() } @@ -61,7 +64,7 @@ impl CSSRule { // Given a StyleCssRule, create a new instance of a derived class of // CSSRule based on which rule it is - pub fn new_specific(window: &Window, parent: &CSSStyleSheet, + pub fn new_specific(window: &Window, parent: Option<&CSSStyleSheet>, rule: StyleCssRule) -> Root<CSSRule> { // be sure to update the match in as_specific when this is updated match rule { @@ -73,6 +76,21 @@ impl CSSRule { StyleCssRule::Viewport(s) => Root::upcast(CSSViewportRule::new(window, parent, s)), } } + + /// Sets owner sheet/rule to null + pub fn detach(&self) { + self.deparent(); + // should set parent rule to None when we add parent rule support + } + + /// Sets owner sheet to null (and does the same for all children) + pub fn deparent(&self) { + self.parent.set(None); + // https://github.com/w3c/csswg-drafts/issues/722 + // Spec doesn't ask us to do this, but it makes sense + // and browsers implement this behavior + self.as_specific().deparent_children(); + } } impl CSSRuleMethods for CSSRule { @@ -100,4 +118,8 @@ impl CSSRuleMethods for CSSRule { pub trait SpecificCSSRule { fn ty(&self) -> u16; fn get_css(&self) -> DOMString; + /// Remove CSSStyleSheet parent from all transitive children + fn deparent_children(&self) { + // most CSSRules do nothing here + } } diff --git a/components/script/dom/cssrulelist.rs b/components/script/dom/cssrulelist.rs index 1c383403a00..deb6b93e8b1 100644 --- a/components/script/dom/cssrulelist.rs +++ b/components/script/dom/cssrulelist.rs @@ -2,61 +2,248 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::CSSRuleListBinding; use dom::bindings::codegen::Bindings::CSSRuleListBinding::CSSRuleListMethods; +use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; +use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::js::{JS, MutNullableHeap, Root}; use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object}; +use dom::csskeyframerule::CSSKeyframeRule; use dom::cssrule::CSSRule; use dom::cssstylesheet::CSSStyleSheet; use dom::window::Window; -use style::stylesheets::CssRules; +use parking_lot::RwLock; +use std::sync::Arc; +use style::parser::ParserContextExtraData; +use style::stylesheets::{CssRules, KeyframesRule, Origin}; +use style::stylesheets::CssRule as StyleCssRule; +no_jsmanaged_fields!(RulesSource); no_jsmanaged_fields!(CssRules); #[dom_struct] pub struct CSSRuleList { reflector_: Reflector, - sheet: JS<CSSStyleSheet>, + sheet: MutNullableHeap<JS<CSSStyleSheet>>, #[ignore_heap_size_of = "Arc"] - rules: CssRules, - dom_rules: Vec<MutNullableHeap<JS<CSSRule>>> + rules: RulesSource, + dom_rules: DOMRefCell<Vec<MutNullableHeap<JS<CSSRule>>>> +} + +pub enum RulesSource { + Rules(CssRules), + Keyframes(Arc<RwLock<KeyframesRule>>), } impl CSSRuleList { #[allow(unrooted_must_root)] - pub fn new_inherited(sheet: &CSSStyleSheet, rules: CssRules) -> CSSRuleList { - let dom_rules = rules.0.read().iter().map(|_| MutNullableHeap::new(None)).collect(); + pub fn new_inherited(sheet: Option<&CSSStyleSheet>, rules: RulesSource) -> CSSRuleList { + let dom_rules = match rules { + RulesSource::Rules(ref rules) => { + rules.0.read().iter().map(|_| MutNullableHeap::new(None)).collect() + } + RulesSource::Keyframes(ref rules) => { + rules.read().keyframes.iter().map(|_| MutNullableHeap::new(None)).collect() + } + }; + CSSRuleList { reflector_: Reflector::new(), - sheet: JS::from_ref(sheet), + sheet: MutNullableHeap::new(sheet), rules: rules, - dom_rules: dom_rules, + dom_rules: DOMRefCell::new(dom_rules), } } #[allow(unrooted_must_root)] - pub fn new(window: &Window, sheet: &CSSStyleSheet, rules: CssRules) -> Root<CSSRuleList> { + pub fn new(window: &Window, sheet: Option<&CSSStyleSheet>, + rules: RulesSource) -> Root<CSSRuleList> { reflect_dom_object(box CSSRuleList::new_inherited(sheet, rules), window, 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<u32> { + use style::stylesheets::SingleRuleParseError; + /// Insert an item into a vector, appending if it is out of bounds + fn insert<T>(vec: &mut Vec<T>, 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 { + panic!("Called insert_rule on non-CssRule-backed CSSRuleList"); + }; + + let global = self.global(); + let window = global.as_window(); + let doc = window.Document(); + let index = idx as usize; + + + 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))); + Ok((idx)) + } + + // https://drafts.csswg.org/cssom/#remove-a-css-rule + // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-deleterule + // In case of a keyframe rule, index must be valid. + pub fn remove_rule(&self, index: u32) -> ErrorResult { + let index = index as usize; + + match self.rules { + RulesSource::Rules(ref css_rules) => { + // https://drafts.csswg.org/cssom/#remove-a-css-rule + { + let rules = css_rules.0.read(); + + // Step 1, 2 + if index >= rules.len() { + return Err(Error::IndexSize); + } + + // Step 3 + let ref rule = rules[index]; + + // Step 4 + if let StyleCssRule::Namespace(..) = *rule { + if !CssRules::only_ns_or_import(&rules) { + return Err(Error::InvalidState); + } + } + } + + // Step 5, 6 + let mut dom_rules = self.dom_rules.borrow_mut(); + css_rules.0.write().remove(index); + dom_rules[index].get().map(|r| r.detach()); + dom_rules.remove(index); + Ok(()) + } + RulesSource::Keyframes(ref kf) => { + // https://drafts.csswg.org/css-animations/#dom-csskeyframesrule-deleterule + let mut dom_rules = self.dom_rules.borrow_mut(); + dom_rules[index].get().map(|r| r.detach()); + dom_rules.remove(index); + kf.write().keyframes.remove(index); + Ok(()) + } + } + } + + // Remove parent stylesheets from all children + pub fn deparent_all(&self) { + for rule in self.dom_rules.borrow().iter() { + rule.get().map(|r| Root::upcast(r).deparent()); + } + } + + pub fn item(&self, idx: u32) -> Option<Root<CSSRule>> { + self.dom_rules.borrow().get(idx as usize).map(|rule| { + rule.or_init(|| { + let sheet = self.sheet.get(); + let sheet = sheet.as_ref().map(|sheet| &**sheet); + match self.rules { + RulesSource::Rules(ref rules) => { + CSSRule::new_specific(self.global().as_window(), + sheet, + rules.0.read()[idx as usize].clone()) + } + RulesSource::Keyframes(ref rules) => { + Root::upcast(CSSKeyframeRule::new(self.global().as_window(), + sheet, + rules.read() + .keyframes[idx as usize] + .clone())) + } + } + + }) + }) + } + + /// Add a rule to the list of DOM rules. This list is lazy, + /// so we just append a placeholder. + /// + /// Should only be called for keyframes-backed rules, use insert_rule + /// for CssRules-backed rules + pub fn append_lazy_dom_rule(&self) { + if let RulesSource::Rules(..) = self.rules { + panic!("Can only call append_lazy_rule with keyframes-backed CSSRules"); + } + self.dom_rules.borrow_mut().push(MutNullableHeap::new(None)); + } } impl CSSRuleListMethods for CSSRuleList { // https://drafts.csswg.org/cssom/#ref-for-dom-cssrulelist-item-1 fn Item(&self, idx: u32) -> Option<Root<CSSRule>> { - self.dom_rules.get(idx as usize).map(|rule| { - rule.or_init(|| { - CSSRule::new_specific(self.global().as_window(), - &self.sheet, - self.rules.0.read()[idx as usize].clone()) - }) - }) + self.item(idx) } // https://drafts.csswg.org/cssom/#dom-cssrulelist-length fn Length(&self) -> u32 { - self.dom_rules.len() as u32 + self.dom_rules.borrow().len() as u32 } // check-tidy: no specs after this line diff --git a/components/script/dom/cssstylerule.rs b/components/script/dom/cssstylerule.rs index 30726018ca9..7d776655147 100644 --- a/components/script/dom/cssstylerule.rs +++ b/components/script/dom/cssstylerule.rs @@ -22,7 +22,7 @@ pub struct CSSStyleRule { } impl CSSStyleRule { - fn new_inherited(parent: &CSSStyleSheet, stylerule: Arc<RwLock<StyleRule>>) -> CSSStyleRule { + fn new_inherited(parent: Option<&CSSStyleSheet>, stylerule: Arc<RwLock<StyleRule>>) -> CSSStyleRule { CSSStyleRule { cssrule: CSSRule::new_inherited(parent), stylerule: stylerule, @@ -30,7 +30,7 @@ impl CSSStyleRule { } #[allow(unrooted_must_root)] - pub fn new(window: &Window, parent: &CSSStyleSheet, + pub fn new(window: &Window, parent: Option<&CSSStyleSheet>, stylerule: Arc<RwLock<StyleRule>>) -> Root<CSSStyleRule> { reflect_dom_object(box CSSStyleRule::new_inherited(parent, stylerule), window, diff --git a/components/script/dom/cssstylesheet.rs b/components/script/dom/cssstylesheet.rs index d5a9342a75a..2e2ac45d867 100644 --- a/components/script/dom/cssstylesheet.rs +++ b/components/script/dom/cssstylesheet.rs @@ -4,10 +4,11 @@ use dom::bindings::codegen::Bindings::CSSStyleSheetBinding; use dom::bindings::codegen::Bindings::CSSStyleSheetBinding::CSSStyleSheetMethods; +use dom::bindings::error::{ErrorResult, Fallible}; use dom::bindings::js::{JS, Root, MutNullableHeap}; use dom::bindings::reflector::{reflect_dom_object, Reflectable}; use dom::bindings::str::DOMString; -use dom::cssrulelist::CSSRuleList; +use dom::cssrulelist::{CSSRuleList, RulesSource}; use dom::stylesheet::StyleSheet; use dom::window::Window; use std::sync::Arc; @@ -40,12 +41,33 @@ impl CSSStyleSheet { window, CSSStyleSheetBinding::Wrap) } + + fn rulelist(&self) -> Root<CSSRuleList> { + self.rulelist.or_init(|| CSSRuleList::new(self.global().as_window(), + Some(self), + RulesSource::Rules(self.style_stylesheet + .rules.clone()))) + } } impl CSSStyleSheetMethods for CSSStyleSheet { // https://drafts.csswg.org/cssom/#dom-cssstylesheet-cssrules fn CssRules(&self) -> Root<CSSRuleList> { - self.rulelist.or_init(|| CSSRuleList::new(self.global().as_window(), self, self.style_stylesheet.rules.clone())) + // XXXManishearth check origin clean flag + // https://github.com/servo/servo/issues/14327 + self.rulelist() + } + + // https://drafts.csswg.org/cssom/#dom-cssstylesheet-insertrule + fn InsertRule(&self, rule: DOMString, index: u32) -> Fallible<u32> { + // XXXManishearth check origin clean flag + self.rulelist().insert_rule(&rule, index, /* nested */ false) + } + + // https://drafts.csswg.org/cssom/#dom-cssstylesheet-deleterule + fn DeleteRule(&self, index: u32) -> ErrorResult { + // XXXManishearth check origin clean flag + self.rulelist().remove_rule(index) } } diff --git a/components/script/dom/cssviewportrule.rs b/components/script/dom/cssviewportrule.rs index f534c535a64..b324b0c64f5 100644 --- a/components/script/dom/cssviewportrule.rs +++ b/components/script/dom/cssviewportrule.rs @@ -22,7 +22,7 @@ pub struct CSSViewportRule { } impl CSSViewportRule { - fn new_inherited(parent: &CSSStyleSheet, viewportrule: Arc<RwLock<ViewportRule>>) -> CSSViewportRule { + fn new_inherited(parent: Option<&CSSStyleSheet>, viewportrule: Arc<RwLock<ViewportRule>>) -> CSSViewportRule { CSSViewportRule { cssrule: CSSRule::new_inherited(parent), viewportrule: viewportrule, @@ -30,7 +30,7 @@ impl CSSViewportRule { } #[allow(unrooted_must_root)] - pub fn new(window: &Window, parent: &CSSStyleSheet, + pub fn new(window: &Window, parent: Option<&CSSStyleSheet>, viewportrule: Arc<RwLock<ViewportRule>>) -> Root<CSSViewportRule> { reflect_dom_object(box CSSViewportRule::new_inherited(parent, viewportrule), window, diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index d1f6d8e957f..f311d022470 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -22,6 +22,7 @@ use dom::eventtarget::EventTarget; use dom::globalscope::GlobalScope; use dom::htmlelement::HTMLElement; use dom::node::{Node, document_from_node, window_from_node}; +use dom::stylesheet::StyleSheet as DOMStyleSheet; use dom::virtualmethods::VirtualMethods; use encoding::EncodingRef; use encoding::all::UTF_8; @@ -452,4 +453,9 @@ impl HTMLLinkElementMethods for HTMLLinkElement { // https://html.spec.whatwg.org/multipage/#dom-link-target make_setter!(SetTarget, "target"); + + // https://drafts.csswg.org/cssom/#dom-linkstyle-sheet + fn GetSheet(&self) -> Option<Root<DOMStyleSheet>> { + self.get_cssom_stylesheet().map(Root::upcast) + } } diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index d65153bee31..6a20bf06cdd 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -5,6 +5,7 @@ use cssparser::Parser as CssParser; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::HTMLStyleElementBinding; +use dom::bindings::codegen::Bindings::HTMLStyleElementBinding::HTMLStyleElementMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::inheritance::Castable; use dom::bindings::js::{JS, MutNullableHeap, Root}; @@ -14,6 +15,7 @@ use dom::document::Document; use dom::element::Element; use dom::htmlelement::HTMLElement; use dom::node::{ChildrenMutation, Node, document_from_node, window_from_node}; +use dom::stylesheet::StyleSheet as DOMStyleSheet; use dom::virtualmethods::VirtualMethods; use html5ever_atoms::LocalName; use script_layout_interface::message::Msg; @@ -117,3 +119,10 @@ impl VirtualMethods for HTMLStyleElement { } } } + +impl HTMLStyleElementMethods for HTMLStyleElement { + // https://drafts.csswg.org/cssom/#dom-linkstyle-sheet + fn GetSheet(&self) -> Option<Root<DOMStyleSheet>> { + self.get_cssom_stylesheet().map(Root::upcast) + } +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 05ec1963a20..23209d89e07 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -244,6 +244,7 @@ pub mod crypto; pub mod css; pub mod cssfontfacerule; pub mod cssgroupingrule; +pub mod csskeyframerule; pub mod csskeyframesrule; pub mod cssmediarule; pub mod cssnamespacerule; diff --git a/components/script/dom/webidls/CSSGroupingRule.webidl b/components/script/dom/webidls/CSSGroupingRule.webidl index 6a317191ff6..9f8347a17d5 100644 --- a/components/script/dom/webidls/CSSGroupingRule.webidl +++ b/components/script/dom/webidls/CSSGroupingRule.webidl @@ -5,8 +5,8 @@ // https://drafts.csswg.org/cssom/#the-cssgroupingrule-interface [Exposed=Window] interface CSSGroupingRule : CSSRule { - // [SameObject] readonly attribute CSSRuleList cssRules; - // unsigned long insertRule(DOMString rule, unsigned long index); - // void deleteRule(unsigned long index); + [SameObject] readonly attribute CSSRuleList cssRules; + [Throws] unsigned long insertRule(DOMString rule, unsigned long index); + [Throws] void deleteRule(unsigned long index); }; diff --git a/components/script/dom/webidls/CSSKeyframeRule.webidl b/components/script/dom/webidls/CSSKeyframeRule.webidl new file mode 100644 index 00000000000..5458440be6d --- /dev/null +++ b/components/script/dom/webidls/CSSKeyframeRule.webidl @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// https://drafts.csswg.org/css-animations/#interface-csskeyframerule +[Exposed=Window] +interface CSSKeyframeRule : CSSRule { + // attribute DOMString keyText; + // readonly attribute CSSStyleDeclaration style; +}; diff --git a/components/script/dom/webidls/CSSKeyframesRule.webidl b/components/script/dom/webidls/CSSKeyframesRule.webidl index db152d72850..34d45e1a357 100644 --- a/components/script/dom/webidls/CSSKeyframesRule.webidl +++ b/components/script/dom/webidls/CSSKeyframesRule.webidl @@ -6,9 +6,9 @@ [Exposed=Window] interface CSSKeyframesRule : CSSRule { // attribute DOMString name; - // readonly attribute CSSRuleList cssRules; + readonly attribute CSSRuleList cssRules; - // void appendRule(DOMString rule); - // void deleteRule(DOMString select); - // CSSKeyframeRule? findRule(DOMString select); + void appendRule(DOMString rule); + void deleteRule(DOMString select); + CSSKeyframeRule? findRule(DOMString select); }; diff --git a/components/script/dom/webidls/CSSNamespaceRule.webidl b/components/script/dom/webidls/CSSNamespaceRule.webidl index a8d6b61548f..aa1ce87e289 100644 --- a/components/script/dom/webidls/CSSNamespaceRule.webidl +++ b/components/script/dom/webidls/CSSNamespaceRule.webidl @@ -5,6 +5,6 @@ // https://drafts.csswg.org/cssom/#the-cssnamespacerule-interface [Exposed=Window] interface CSSNamespaceRule : CSSRule { - // readonly attribute DOMString namespaceURI; - // readonly attribute DOMString prefix; + readonly attribute DOMString namespaceURI; + readonly attribute DOMString prefix; }; diff --git a/components/script/dom/webidls/CSSStyleSheet.webidl b/components/script/dom/webidls/CSSStyleSheet.webidl index 99ab3234705..6fba0cf983a 100644 --- a/components/script/dom/webidls/CSSStyleSheet.webidl +++ b/components/script/dom/webidls/CSSStyleSheet.webidl @@ -7,6 +7,6 @@ interface CSSStyleSheet : StyleSheet { // readonly attribute CSSRule? ownerRule; [SameObject] readonly attribute CSSRuleList cssRules; - // unsigned long insertRule(DOMString rule, unsigned long index); - // void deleteRule(unsigned long index); + [Throws] unsigned long insertRule(DOMString rule, unsigned long index); + [Throws] void deleteRule(unsigned long index); }; diff --git a/components/script/dom/webidls/HTMLLinkElement.webidl b/components/script/dom/webidls/HTMLLinkElement.webidl index 8c1bf496590..e7bec059efe 100644 --- a/components/script/dom/webidls/HTMLLinkElement.webidl +++ b/components/script/dom/webidls/HTMLLinkElement.webidl @@ -15,7 +15,7 @@ interface HTMLLinkElement : HTMLElement { // also has obsolete members }; -//HTMLLinkElement implements LinkStyle; +HTMLLinkElement implements LinkStyle; // https://html.spec.whatwg.org/multipage/#HTMLLinkElement-partial partial interface HTMLLinkElement { diff --git a/components/script/dom/webidls/HTMLStyleElement.webidl b/components/script/dom/webidls/HTMLStyleElement.webidl index dd766f41d22..78926c2c1a8 100644 --- a/components/script/dom/webidls/HTMLStyleElement.webidl +++ b/components/script/dom/webidls/HTMLStyleElement.webidl @@ -8,4 +8,4 @@ interface HTMLStyleElement : HTMLElement { // attribute DOMString type; // attribute boolean scoped; }; -//HTMLStyleElement implements LinkStyle; +HTMLStyleElement implements LinkStyle; diff --git a/components/script/dom/webidls/StyleSheet.webidl b/components/script/dom/webidls/StyleSheet.webidl index a63e2a41f01..336bc6b282c 100644 --- a/components/script/dom/webidls/StyleSheet.webidl +++ b/components/script/dom/webidls/StyleSheet.webidl @@ -15,3 +15,9 @@ interface StyleSheet { // [SameObject, PutForwards=mediaText] readonly attribute MediaList media; // attribute boolean disabled; }; + +// https://drafts.csswg.org/cssom/#the-linkstyle-interface +[NoInterfaceObject] +interface LinkStyle { + readonly attribute StyleSheet? sheet; +}; |