aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/script/dom/cssfontfacerule.rs4
-rw-r--r--components/script/dom/cssgroupingrule.rs49
-rw-r--r--components/script/dom/csskeyframerule.rs50
-rw-r--r--components/script/dom/csskeyframesrule.rs84
-rw-r--r--components/script/dom/cssmediarule.rs7
-rw-r--r--components/script/dom/cssnamespacerule.rs19
-rw-r--r--components/script/dom/cssrule.rs30
-rw-r--r--components/script/dom/cssrulelist.rs221
-rw-r--r--components/script/dom/cssstylerule.rs4
-rw-r--r--components/script/dom/cssstylesheet.rs26
-rw-r--r--components/script/dom/cssviewportrule.rs4
-rw-r--r--components/script/dom/htmllinkelement.rs6
-rw-r--r--components/script/dom/htmlstyleelement.rs9
-rw-r--r--components/script/dom/mod.rs1
-rw-r--r--components/script/dom/webidls/CSSGroupingRule.webidl6
-rw-r--r--components/script/dom/webidls/CSSKeyframeRule.webidl10
-rw-r--r--components/script/dom/webidls/CSSKeyframesRule.webidl8
-rw-r--r--components/script/dom/webidls/CSSNamespaceRule.webidl4
-rw-r--r--components/script/dom/webidls/CSSStyleSheet.webidl4
-rw-r--r--components/script/dom/webidls/HTMLLinkElement.webidl2
-rw-r--r--components/script/dom/webidls/HTMLStyleElement.webidl2
-rw-r--r--components/script/dom/webidls/StyleSheet.webidl6
-rw-r--r--components/style/font_face.rs4
-rw-r--r--components/style/keyframes.rs33
-rw-r--r--components/style/stylesheets.rs111
-rw-r--r--tests/wpt/metadata-css/cssom-1_dev/html/css-style-declaration-modifications.htm.ini1
-rw-r--r--tests/wpt/metadata-css/cssom-1_dev/html/cssimportrule.htm.ini1
-rw-r--r--tests/wpt/metadata-css/cssom-1_dev/html/cssstylerule.htm.ini19
-rw-r--r--tests/wpt/metadata-css/cssom-1_dev/html/interfaces.htm.ini102
-rw-r--r--tests/wpt/metadata-css/cssom-1_dev/html/medialist-interfaces-002.htm.ini3
-rw-r--r--tests/wpt/metadata-css/cssom-1_dev/html/style-sheet-interfaces-002.htm.ini8
-rw-r--r--tests/wpt/metadata/html/dom/interfaces.html.ini6
-rw-r--r--tests/wpt/metadata/html/semantics/document-metadata/styling/LinkStyle.html.ini3
-rw-r--r--tests/wpt/mozilla/tests/mozilla/interfaces.html1
34 files changed, 656 insertions, 192 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;
+};
diff --git a/components/style/font_face.rs b/components/style/font_face.rs
index 62d8f6ade19..4a5f34237ad 100644
--- a/components/style/font_face.rs
+++ b/components/style/font_face.rs
@@ -26,11 +26,11 @@ impl ToCss for Source {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
Source::Url(ref url) => {
- try!(dest.write_str("local(\""));
+ try!(dest.write_str("url(\""));
try!(url.to_css(dest));
},
Source::Local(ref family) => {
- try!(dest.write_str("url(\""));
+ try!(dest.write_str("local(\""));
try!(family.to_css(dest));
},
}
diff --git a/components/style/keyframes.rs b/components/style/keyframes.rs
index c13cd1b5431..7c9b969a210 100644
--- a/components/style/keyframes.rs
+++ b/components/style/keyframes.rs
@@ -3,15 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, RuleListParser};
-use cssparser::{DeclarationListParser, DeclarationParser};
+use cssparser::{DeclarationListParser, DeclarationParser, parse_one_rule};
use parking_lot::RwLock;
-use parser::{ParserContext, log_css_error};
+use parser::{ParserContext, ParserContextExtraData, log_css_error};
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
use properties::PropertyDeclarationParseResult;
use properties::animated_properties::TransitionProperty;
+use servo_url::ServoUrl;
use std::fmt;
use std::sync::Arc;
use style_traits::ToCss;
+use stylesheets::{MemoryHoleReporter, Origin};
/// A number from 1 to 100, indicating the percentage of the animation where
/// this keyframe should run.
@@ -68,6 +70,11 @@ impl KeyframeSelector {
pub fn new_for_unit_testing(percentages: Vec<KeyframePercentage>) -> KeyframeSelector {
KeyframeSelector(percentages)
}
+
+ pub fn parse(input: &mut Parser) -> Result<Self, ()> {
+ input.parse_comma_separated(KeyframePercentage::parse)
+ .map(KeyframeSelector)
+ }
}
/// A keyframe.
@@ -99,6 +106,24 @@ impl ToCss for Keyframe {
}
}
+
+impl Keyframe {
+ pub fn parse(css: &str, origin: Origin,
+ base_url: ServoUrl,
+ extra_data: ParserContextExtraData) -> Result<Arc<RwLock<Self>>, ()> {
+ let error_reporter = Box::new(MemoryHoleReporter);
+ let context = ParserContext::new_with_extra_data(origin, &base_url,
+ error_reporter,
+ extra_data);
+ let mut input = Parser::new(css);
+
+ let mut rule_parser = KeyframeListParser {
+ context: &context,
+ };
+ parse_one_rule(&mut input, &mut rule_parser)
+ }
+}
+
/// A keyframes step value. This can be a synthetised keyframes animation, that
/// is, one autogenerated from the current computed values, or a list of
/// declarations to apply.
@@ -260,8 +285,8 @@ impl<'a> QualifiedRuleParser for KeyframeListParser<'a> {
fn parse_prelude(&mut self, input: &mut Parser) -> Result<Self::Prelude, ()> {
let start = input.position();
- match input.parse_comma_separated(|input| KeyframePercentage::parse(input)) {
- Ok(percentages) => Ok(KeyframeSelector(percentages)),
+ match KeyframeSelector::parse(input) {
+ Ok(sel) => Ok(sel),
Err(()) => {
let message = format!("Invalid keyframe rule: '{}'", input.slice_from(start));
log_css_error(input, start, &message, self.context);
diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs
index 7e8388591a8..6e057e26f37 100644
--- a/components/style/stylesheets.rs
+++ b/components/style/stylesheets.rs
@@ -6,7 +6,7 @@
use {Atom, Prefix, Namespace};
use cssparser::{AtRuleParser, Parser, QualifiedRuleParser, decode_stylesheet_bytes};
-use cssparser::{AtRuleType, RuleListParser, Token};
+use cssparser::{AtRuleType, RuleListParser, SourcePosition, Token, parse_one_rule};
use cssparser::ToCss as ParserToCss;
use encoding::EncodingRef;
use error_reporting::ParseErrorReporter;
@@ -60,6 +60,50 @@ impl From<Vec<CssRule>> for CssRules {
}
}
+impl CssRules {
+ // used in CSSOM
+ pub fn only_ns_or_import(rules: &[CssRule]) -> bool {
+ rules.iter().all(|r| {
+ match *r {
+ CssRule::Namespace(..) /* | CssRule::Import(..) */ => true,
+ _ => false
+ }
+ })
+ }
+
+ // Provides the parser state at a given insertion index
+ pub fn state_at_index(rules: &[CssRule], at: usize) -> State {
+ let mut state = State::Start;
+ if at > 0 {
+ if let Some(rule) = rules.get(at - 1) {
+ state = match *rule {
+ // CssRule::Charset(..) => State::Start,
+ // CssRule::Import(..) => State::Imports,
+ CssRule::Namespace(..) => State::Namespaces,
+ _ => State::Body,
+ };
+ }
+ }
+ state
+ }
+
+ // Provides the maximum allowed parser state at a given index,
+ // searching in reverse. If inserting at this index, the parser
+ // must not be in a state greater than this post-insertion.
+ pub fn state_at_index_rev(rules: &[CssRule], at: usize) -> State {
+ if let Some(rule) = rules.get(at) {
+ match *rule {
+ // CssRule::Charset(..) => State::Start,
+ // CssRule::Import(..) => State::Imports,
+ CssRule::Namespace(..) => State::Namespaces,
+ _ => State::Body,
+ }
+ } else {
+ State::Body
+ }
+ }
+}
+
#[derive(Debug)]
pub struct Stylesheet {
/// List of rules in the order they were found (important for
@@ -92,6 +136,26 @@ pub enum CssRule {
Keyframes(Arc<RwLock<KeyframesRule>>),
}
+/// Error reporter which silently forgets errors
+pub struct MemoryHoleReporter;
+
+impl ParseErrorReporter for MemoryHoleReporter {
+ fn report_error(&self,
+ _: &mut Parser,
+ _: SourcePosition,
+ _: &str) {
+ // do nothing
+ }
+ fn clone(&self) -> Box<ParseErrorReporter + Send + Sync> {
+ Box::new(MemoryHoleReporter)
+ }
+}
+
+pub enum SingleRuleParseError {
+ Syntax,
+ Hierarchy,
+}
+
impl CssRule {
/// Call `f` with the slice of rules directly contained inside this rule.
///
@@ -114,6 +178,39 @@ impl CssRule {
}
}
}
+
+ // input state is None for a nested rule
+ // Returns a parsed CSS rule and the final state of the parser
+ pub fn parse(css: &str, origin: Origin,
+ base_url: ServoUrl,
+ extra_data: ParserContextExtraData,
+ state: Option<State>) -> Result<(Self, State), SingleRuleParseError> {
+ let error_reporter = Box::new(MemoryHoleReporter);
+ let mut namespaces = Namespaces::default();
+ let context = ParserContext::new_with_extra_data(origin, &base_url,
+ error_reporter.clone(),
+ extra_data);
+ let mut input = Parser::new(css);
+
+ // nested rules are in the body state
+ let state = state.unwrap_or(State::Body);
+ let mut rule_parser = TopLevelRuleParser {
+ stylesheet_origin: origin,
+ context: context,
+ state: Cell::new(state),
+ namespaces: &mut namespaces,
+ };
+ match parse_one_rule(&mut input, &mut rule_parser) {
+ Ok(result) => Ok((result, rule_parser.state.get())),
+ Err(_) => {
+ if let State::Invalid = rule_parser.state.get() {
+ Err(SingleRuleParseError::Hierarchy)
+ } else {
+ Err(SingleRuleParseError::Syntax)
+ }
+ }
+ }
+ }
}
impl ToCss for CssRule {
@@ -220,7 +317,6 @@ impl ToCss for StyleRule {
}
}
-
impl Stylesheet {
pub fn from_bytes(bytes: &[u8],
base_url: ServoUrl,
@@ -370,11 +466,12 @@ impl<'b> TopLevelRuleParser<'b> {
}
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
-enum State {
+pub enum State {
Start = 1,
Imports = 2,
Namespaces = 3,
Body = 4,
+ Invalid = 5,
}
@@ -403,6 +500,7 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
// TODO: support @import
return Err(()) // "@import is not supported yet"
} else {
+ self.state.set(State::Invalid);
return Err(()) // "@import must be before any rule but @charset"
}
},
@@ -429,6 +527,7 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
}
)))))
} else {
+ self.state.set(State::Invalid);
return Err(()) // "@namespace must be before any rule but @charset and @import"
}
},
@@ -437,7 +536,11 @@ impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
"charset" => return Err(()), // (insert appropriate error message)
_ => {}
}
-
+ // Don't allow starting with an invalid state
+ if self.state.get() > State::Body {
+ self.state.set(State::Invalid);
+ return Err(());
+ }
self.state.set(State::Body);
AtRuleParser::parse_prelude(&mut self.nested(), name, input)
}
diff --git a/tests/wpt/metadata-css/cssom-1_dev/html/css-style-declaration-modifications.htm.ini b/tests/wpt/metadata-css/cssom-1_dev/html/css-style-declaration-modifications.htm.ini
index 18891538628..1b70b013125 100644
--- a/tests/wpt/metadata-css/cssom-1_dev/html/css-style-declaration-modifications.htm.ini
+++ b/tests/wpt/metadata-css/cssom-1_dev/html/css-style-declaration-modifications.htm.ini
@@ -1,6 +1,5 @@
[css-style-declaration-modifications.htm]
type: testharness
- expected: ERROR
[CSSStyleDeclaration_accessible]
expected: FAIL
diff --git a/tests/wpt/metadata-css/cssom-1_dev/html/cssimportrule.htm.ini b/tests/wpt/metadata-css/cssom-1_dev/html/cssimportrule.htm.ini
index b6eb6b3a39c..b09eb56a50f 100644
--- a/tests/wpt/metadata-css/cssom-1_dev/html/cssimportrule.htm.ini
+++ b/tests/wpt/metadata-css/cssom-1_dev/html/cssimportrule.htm.ini
@@ -1,6 +1,5 @@
[cssimportrule.htm]
type: testharness
- expected: ERROR
[CSSRule and CSSImportRule types]
expected: FAIL
diff --git a/tests/wpt/metadata-css/cssom-1_dev/html/cssstylerule.htm.ini b/tests/wpt/metadata-css/cssom-1_dev/html/cssstylerule.htm.ini
index 42a59247827..70d0be16aa7 100644
--- a/tests/wpt/metadata-css/cssom-1_dev/html/cssstylerule.htm.ini
+++ b/tests/wpt/metadata-css/cssom-1_dev/html/cssstylerule.htm.ini
@@ -1,3 +1,20 @@
[cssstylerule.htm]
type: testharness
- expected: ERROR
+ [Rule_type_property]
+ expected: FAIL
+
+ [Rule_properties]
+ expected: FAIL
+
+ [Rule_properties_readonly]
+ expected: FAIL
+
+ [Rule_properties_values]
+ expected: FAIL
+
+ [StyleRule_properties]
+ expected: FAIL
+
+ [StyleRule_properties_values]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata-css/cssom-1_dev/html/interfaces.htm.ini b/tests/wpt/metadata-css/cssom-1_dev/html/interfaces.htm.ini
index 02c46f56ee4..8f0e47d7557 100644
--- a/tests/wpt/metadata-css/cssom-1_dev/html/interfaces.htm.ini
+++ b/tests/wpt/metadata-css/cssom-1_dev/html/interfaces.htm.ini
@@ -120,51 +120,18 @@
[CSSStyleSheet interface: attribute ownerRule]
expected: FAIL
- [CSSStyleSheet interface: operation insertRule(DOMString,unsigned long)]
- expected: FAIL
-
- [CSSStyleSheet interface: operation deleteRule(unsigned long)]
- expected: FAIL
-
- [CSSStyleSheet must be primary interface of style_element.sheet]
- expected: FAIL
-
- [Stringification of style_element.sheet]
- expected: FAIL
-
[CSSStyleSheet interface: style_element.sheet must inherit property "ownerRule" with the proper type (0)]
expected: FAIL
- [CSSStyleSheet interface: style_element.sheet must inherit property "cssRules" with the proper type (1)]
- expected: FAIL
-
- [CSSStyleSheet interface: style_element.sheet must inherit property "insertRule" with the proper type (2)]
- expected: FAIL
-
- [CSSStyleSheet interface: calling insertRule(DOMString,unsigned long) on style_element.sheet with too few arguments must throw TypeError]
- expected: FAIL
-
- [CSSStyleSheet interface: style_element.sheet must inherit property "deleteRule" with the proper type (3)]
- expected: FAIL
-
- [CSSStyleSheet interface: calling deleteRule(unsigned long) on style_element.sheet with too few arguments must throw TypeError]
- expected: FAIL
-
[StyleSheet interface: style_element.sheet must inherit property "type" with the proper type (0)]
expected: FAIL
- [StyleSheet interface: style_element.sheet must inherit property "href" with the proper type (1)]
- expected: FAIL
-
[StyleSheet interface: style_element.sheet must inherit property "ownerNode" with the proper type (2)]
expected: FAIL
[StyleSheet interface: style_element.sheet must inherit property "parentStyleSheet" with the proper type (3)]
expected: FAIL
- [StyleSheet interface: style_element.sheet must inherit property "title" with the proper type (4)]
- expected: FAIL
-
[StyleSheet interface: style_element.sheet must inherit property "media" with the proper type (5)]
expected: FAIL
@@ -177,21 +144,6 @@
[CSSRuleList interface: existence and properties of interface prototype object]
expected: FAIL
- [CSSRuleList must be primary interface of style_element.sheet.cssRules]
- expected: FAIL
-
- [Stringification of style_element.sheet.cssRules]
- expected: FAIL
-
- [CSSRuleList interface: style_element.sheet.cssRules must inherit property "item" with the proper type (0)]
- expected: FAIL
-
- [CSSRuleList interface: calling item(unsigned long) on style_element.sheet.cssRules with too few arguments must throw TypeError]
- expected: FAIL
-
- [CSSRuleList interface: style_element.sheet.cssRules must inherit property "length" with the proper type (1)]
- expected: FAIL
-
[CSSRule interface: attribute parentRule]
expected: FAIL
@@ -201,54 +153,15 @@
[CSSStyleRule interface: attribute style]
expected: FAIL
- [CSSStyleRule must be primary interface of style_element.sheet.cssRules[0\]]
- expected: FAIL
-
- [Stringification of style_element.sheet.cssRules[0\]]
- expected: FAIL
-
[CSSStyleRule interface: style_element.sheet.cssRules[0\] must inherit property "selectorText" with the proper type (0)]
expected: FAIL
[CSSStyleRule interface: style_element.sheet.cssRules[0\] must inherit property "style" with the proper type (1)]
expected: FAIL
- [CSSRule interface: style_element.sheet.cssRules[0\] must inherit property "STYLE_RULE" with the proper type (0)]
- expected: FAIL
-
- [CSSRule interface: style_element.sheet.cssRules[0\] must inherit property "CHARSET_RULE" with the proper type (1)]
- expected: FAIL
-
- [CSSRule interface: style_element.sheet.cssRules[0\] must inherit property "IMPORT_RULE" with the proper type (2)]
- expected: FAIL
-
- [CSSRule interface: style_element.sheet.cssRules[0\] must inherit property "MEDIA_RULE" with the proper type (3)]
- expected: FAIL
-
- [CSSRule interface: style_element.sheet.cssRules[0\] must inherit property "FONT_FACE_RULE" with the proper type (4)]
- expected: FAIL
-
- [CSSRule interface: style_element.sheet.cssRules[0\] must inherit property "PAGE_RULE" with the proper type (5)]
- expected: FAIL
-
- [CSSRule interface: style_element.sheet.cssRules[0\] must inherit property "MARGIN_RULE" with the proper type (6)]
- expected: FAIL
-
- [CSSRule interface: style_element.sheet.cssRules[0\] must inherit property "NAMESPACE_RULE" with the proper type (7)]
- expected: FAIL
-
- [CSSRule interface: style_element.sheet.cssRules[0\] must inherit property "type" with the proper type (8)]
- expected: FAIL
-
- [CSSRule interface: style_element.sheet.cssRules[0\] must inherit property "cssText" with the proper type (9)]
- expected: FAIL
-
[CSSRule interface: style_element.sheet.cssRules[0\] must inherit property "parentRule" with the proper type (10)]
expected: FAIL
- [CSSRule interface: style_element.sheet.cssRules[0\] must inherit property "parentStyleSheet" with the proper type (11)]
- expected: FAIL
-
[CSSImportRule interface: existence and properties of interface object]
expected: FAIL
@@ -270,15 +183,6 @@
[CSSImportRule interface: attribute styleSheet]
expected: FAIL
- [CSSGroupingRule interface: attribute cssRules]
- expected: FAIL
-
- [CSSGroupingRule interface: operation insertRule(DOMString,unsigned long)]
- expected: FAIL
-
- [CSSGroupingRule interface: operation deleteRule(unsigned long)]
- expected: FAIL
-
[CSSMediaRule interface: attribute media]
expected: FAIL
@@ -318,12 +222,6 @@
[CSSMarginRule interface: attribute style]
expected: FAIL
- [CSSNamespaceRule interface: attribute namespaceURI]
- expected: FAIL
-
- [CSSNamespaceRule interface: attribute prefix]
- expected: FAIL
-
[CSSStyleDeclaration interface: attribute parentRule]
expected: FAIL
diff --git a/tests/wpt/metadata-css/cssom-1_dev/html/medialist-interfaces-002.htm.ini b/tests/wpt/metadata-css/cssom-1_dev/html/medialist-interfaces-002.htm.ini
index e2209fd3d2b..13f305b4464 100644
--- a/tests/wpt/metadata-css/cssom-1_dev/html/medialist-interfaces-002.htm.ini
+++ b/tests/wpt/metadata-css/cssom-1_dev/html/medialist-interfaces-002.htm.ini
@@ -1,8 +1,5 @@
[medialist-interfaces-002.htm]
type: testharness
- [deleteMedium_called_without_argument]
- expected: FAIL
-
[deleteMedium_removes_correct_medium]
expected: FAIL
diff --git a/tests/wpt/metadata-css/cssom-1_dev/html/style-sheet-interfaces-002.htm.ini b/tests/wpt/metadata-css/cssom-1_dev/html/style-sheet-interfaces-002.htm.ini
deleted file mode 100644
index fc428958812..00000000000
--- a/tests/wpt/metadata-css/cssom-1_dev/html/style-sheet-interfaces-002.htm.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[style-sheet-interfaces-002.htm]
- type: testharness
- [add_rule]
- expected: FAIL
-
- [delete_rule]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini
index bea6ff2acb4..e00be762510 100644
--- a/tests/wpt/metadata/html/dom/interfaces.html.ini
+++ b/tests/wpt/metadata/html/dom/interfaces.html.ini
@@ -1359,9 +1359,6 @@
[HTMLLinkElement interface: document.createElement("link") must inherit property "sizes" with the proper type (7)]
expected: FAIL
- [HTMLLinkElement interface: document.createElement("link") must inherit property "sheet" with the proper type (11)]
- expected: FAIL
-
[HTMLMetaElement interface: attribute httpEquiv]
expected: FAIL
@@ -1392,9 +1389,6 @@
[HTMLStyleElement interface: document.createElement("style") must inherit property "scoped" with the proper type (2)]
expected: FAIL
- [HTMLStyleElement interface: document.createElement("style") must inherit property "sheet" with the proper type (3)]
- expected: FAIL
-
[HTMLBodyElement interface: attribute link]
expected: FAIL
diff --git a/tests/wpt/metadata/html/semantics/document-metadata/styling/LinkStyle.html.ini b/tests/wpt/metadata/html/semantics/document-metadata/styling/LinkStyle.html.ini
index 60263e45718..47d2fac50fc 100644
--- a/tests/wpt/metadata/html/semantics/document-metadata/styling/LinkStyle.html.ini
+++ b/tests/wpt/metadata/html/semantics/document-metadata/styling/LinkStyle.html.ini
@@ -3,9 +3,6 @@
[The LinkStyle interface's sheet attribute must return null; the disabled attribute must be false]
expected: FAIL
- [The LinkStyle interface's sheet attribute must return null if the corresponding element is not in a Document]
- expected: FAIL
-
[The LinkStyle interface's sheet attribute must return StyleSheet object; the disabled attribute must be same as the StyleSheet's disabled attribute]
expected: FAIL
diff --git a/tests/wpt/mozilla/tests/mozilla/interfaces.html b/tests/wpt/mozilla/tests/mozilla/interfaces.html
index debc89bf675..1e09f096618 100644
--- a/tests/wpt/mozilla/tests/mozilla/interfaces.html
+++ b/tests/wpt/mozilla/tests/mozilla/interfaces.html
@@ -22,6 +22,7 @@ test_interfaces([
"CSS",
"CSSFontFaceRule",
"CSSGroupingRule",
+ "CSSKeyframeRule",
"CSSKeyframesRule",
"CSSMediaRule",
"CSSNamespaceRule",