From b4a83b6cec77a0e27362f85542e4b588301fc0a2 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 3 Jan 2017 11:10:12 -0800 Subject: [PATCH] CSSOM bits for @supports: CSSConditionRule and CSSSupportsRule, with conditionText attribute --- components/script/dom/bindings/trace.rs | 7 ++ components/script/dom/cssconditionrule.rs | 53 +++++++++++++ components/script/dom/cssmediarule.rs | 24 +++++- components/script/dom/cssrule.rs | 4 + components/script/dom/csssupportsrule.rs | 77 +++++++++++++++++++ components/script/dom/mod.rs | 2 + .../dom/webidls/CSSConditionRule.webidl | 9 +++ .../script/dom/webidls/CSSMediaRule.webidl | 3 +- components/script/dom/webidls/CSSRule.webidl | 4 + .../script/dom/webidls/CSSSupportsRule.webidl | 8 ++ components/style/parser.rs | 7 +- components/url/lib.rs | 6 ++ 12 files changed, 199 insertions(+), 5 deletions(-) create mode 100644 components/script/dom/cssconditionrule.rs create mode 100644 components/script/dom/csssupportsrule.rs create mode 100644 components/script/dom/webidls/CSSConditionRule.webidl create mode 100644 components/script/dom/webidls/CSSSupportsRule.webidl diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 850bef189c7..6f211f82bef 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -99,6 +99,7 @@ use style::media_queries::MediaList; use style::properties::PropertyDeclarationBlock; use style::selector_parser::{PseudoElement, Snapshot}; use style::stylesheets::{CssRules, KeyframesRule, MediaRule, NamespaceRule, StyleRule, ImportRule}; +use style::stylesheets::SupportsRule; use style::values::specified::Length; use style::viewport::ViewportRule; use time::Duration; @@ -531,6 +532,12 @@ unsafe impl JSTraceable for RwLock { } } +unsafe impl JSTraceable for RwLock { + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing. + } +} + unsafe impl JSTraceable for RwLock { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. diff --git a/components/script/dom/cssconditionrule.rs b/components/script/dom/cssconditionrule.rs new file mode 100644 index 00000000000..dace5f612c7 --- /dev/null +++ b/components/script/dom/cssconditionrule.rs @@ -0,0 +1,53 @@ +/* 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::CSSConditionRuleBinding::CSSConditionRuleMethods; +use dom::bindings::inheritance::Castable; +use dom::bindings::str::DOMString; +use dom::cssgroupingrule::CSSGroupingRule; +use dom::cssmediarule::CSSMediaRule; +use dom::cssstylesheet::CSSStyleSheet; +use dom::csssupportsrule::CSSSupportsRule; +use parking_lot::RwLock; +use std::sync::Arc; +use style::stylesheets::CssRules as StyleCssRules; + +#[dom_struct] +pub struct CSSConditionRule { + cssgroupingrule: CSSGroupingRule, +} + +impl CSSConditionRule { + pub fn new_inherited(parent_stylesheet: &CSSStyleSheet, + rules: Arc>) -> CSSConditionRule { + CSSConditionRule { + cssgroupingrule: CSSGroupingRule::new_inherited(parent_stylesheet, rules), + } + } + +} + +impl CSSConditionRuleMethods for CSSConditionRule { + /// https://drafts.csswg.org/css-conditional-3/#dom-cssconditionrule-conditiontext + fn ConditionText(&self) -> DOMString { + if let Some(rule) = self.downcast::() { + rule.get_condition_text() + } else if let Some(rule) = self.downcast::() { + rule.get_condition_text() + } else { + unreachable!() + } + } + + /// https://drafts.csswg.org/css-conditional-3/#dom-cssconditionrule-conditiontext + fn SetConditionText(&self, text: DOMString) { + if let Some(rule) = self.downcast::() { + rule.set_condition_text(text) + } else if let Some(rule) = self.downcast::() { + rule.set_condition_text(text) + } else { + unreachable!() + } + } +} diff --git a/components/script/dom/cssmediarule.rs b/components/script/dom/cssmediarule.rs index b6b04dde9d8..438b390aea5 100644 --- a/components/script/dom/cssmediarule.rs +++ b/components/script/dom/cssmediarule.rs @@ -2,24 +2,26 @@ * 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::CSSMediaRuleBinding; use dom::bindings::codegen::Bindings::CSSMediaRuleBinding::CSSMediaRuleMethods; use dom::bindings::js::{MutNullableJS, Root}; use dom::bindings::reflector::{DomObject, reflect_dom_object}; use dom::bindings::str::DOMString; -use dom::cssgroupingrule::CSSGroupingRule; +use dom::cssconditionrule::CSSConditionRule; use dom::cssrule::SpecificCSSRule; use dom::cssstylesheet::CSSStyleSheet; use dom::medialist::MediaList; use dom::window::Window; use parking_lot::RwLock; use std::sync::Arc; +use style::media_queries::parse_media_query_list; use style::stylesheets::MediaRule; use style_traits::ToCss; #[dom_struct] pub struct CSSMediaRule { - cssrule: CSSGroupingRule, + cssrule: CSSConditionRule, #[ignore_heap_size_of = "Arc"] mediarule: Arc>, medialist: MutNullableJS, @@ -30,7 +32,7 @@ impl CSSMediaRule { -> CSSMediaRule { let list = mediarule.read().rules.clone(); CSSMediaRule { - cssrule: CSSGroupingRule::new_inherited(parent_stylesheet, list), + cssrule: CSSConditionRule::new_inherited(parent_stylesheet, list), mediarule: mediarule, medialist: MutNullableJS::new(None), } @@ -48,6 +50,22 @@ impl CSSMediaRule { self.medialist.or_init(|| MediaList::new(self.global().as_window(), self.mediarule.read().media_queries.clone())) } + + /// https://drafts.csswg.org/css-conditional-3/#the-cssmediarule-interface + pub fn get_condition_text(&self) -> DOMString { + let rule = self.mediarule.read(); + let list = rule.media_queries.read(); + list.to_css_string().into() + } + + /// https://drafts.csswg.org/css-conditional-3/#the-cssmediarule-interface + pub fn set_condition_text(&self, text: DOMString) { + let mut input = Parser::new(&text); + let new_medialist = parse_media_query_list(&mut input); + let rule = self.mediarule.read(); + let mut list = rule.media_queries.write(); + *list = new_medialist; + } } impl SpecificCSSRule for CSSMediaRule { diff --git a/components/script/dom/cssrule.rs b/components/script/dom/cssrule.rs index 8323d7e22b0..4fa4041a8d7 100644 --- a/components/script/dom/cssrule.rs +++ b/components/script/dom/cssrule.rs @@ -15,6 +15,7 @@ use dom::cssmediarule::CSSMediaRule; use dom::cssnamespacerule::CSSNamespaceRule; use dom::cssstylerule::CSSStyleRule; use dom::cssstylesheet::CSSStyleSheet; +use dom::csssupportsrule::CSSSupportsRule; use dom::cssviewportrule::CSSViewportRule; use dom::window::Window; use std::cell::Cell; @@ -59,6 +60,8 @@ impl CSSRule { rule as &SpecificCSSRule } else if let Some(rule) = self.downcast::() { rule as &SpecificCSSRule + } else if let Some(rule) = self.downcast::() { + rule as &SpecificCSSRule } else { unreachable!() } @@ -77,6 +80,7 @@ impl CSSRule { StyleCssRule::Media(s) => Root::upcast(CSSMediaRule::new(window, parent_stylesheet, s)), StyleCssRule::Namespace(s) => Root::upcast(CSSNamespaceRule::new(window, parent_stylesheet, s)), StyleCssRule::Viewport(s) => Root::upcast(CSSViewportRule::new(window, parent_stylesheet, s)), + StyleCssRule::Supports(s) => Root::upcast(CSSSupportsRule::new(window, parent_stylesheet, s)), } } diff --git a/components/script/dom/csssupportsrule.rs b/components/script/dom/csssupportsrule.rs new file mode 100644 index 00000000000..3e52fa3afc5 --- /dev/null +++ b/components/script/dom/csssupportsrule.rs @@ -0,0 +1,77 @@ +/* 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 cssparser::Parser; +use dom::bindings::codegen::Bindings::CSSSupportsRuleBinding; +use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; +use dom::bindings::js::Root; +use dom::bindings::reflector::{DomObject, reflect_dom_object}; +use dom::bindings::str::DOMString; +use dom::cssconditionrule::CSSConditionRule; +use dom::cssrule::SpecificCSSRule; +use dom::cssstylesheet::CSSStyleSheet; +use dom::window::Window; +use parking_lot::RwLock; +use std::sync::Arc; +use style::parser::ParserContext; +use style::stylesheets::SupportsRule; +use style::supports::SupportsCondition; +use style_traits::ToCss; + +#[dom_struct] +pub struct CSSSupportsRule { + cssrule: CSSConditionRule, + #[ignore_heap_size_of = "Arc"] + supportsrule: Arc>, +} + +impl CSSSupportsRule { + fn new_inherited(parent_stylesheet: &CSSStyleSheet, supportsrule: Arc>) + -> CSSSupportsRule { + let list = supportsrule.read().rules.clone(); + CSSSupportsRule { + cssrule: CSSConditionRule::new_inherited(parent_stylesheet, list), + supportsrule: supportsrule, + } + } + + #[allow(unrooted_must_root)] + pub fn new(window: &Window, parent_stylesheet: &CSSStyleSheet, + supportsrule: Arc>) -> Root { + reflect_dom_object(box CSSSupportsRule::new_inherited(parent_stylesheet, supportsrule), + window, + CSSSupportsRuleBinding::Wrap) + } + + /// https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface + pub fn get_condition_text(&self) -> DOMString { + let rule = self.supportsrule.read(); + rule.condition.to_css_string().into() + } + + /// https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface + pub fn set_condition_text(&self, text: DOMString) { + let mut input = Parser::new(&text); + let cond = SupportsCondition::parse(&mut input); + if let Ok(cond) = cond { + let url = self.global().as_window().Document().url(); + let context = ParserContext::new_for_cssom(&url); + let enabled = cond.eval(&context); + let mut rule = self.supportsrule.write(); + rule.condition = cond; + rule.enabled = enabled; + } + } +} + +impl SpecificCSSRule for CSSSupportsRule { + fn ty(&self) -> u16 { + use dom::bindings::codegen::Bindings::CSSRuleBinding::CSSRuleConstants; + CSSRuleConstants::SUPPORTS_RULE + } + + fn get_css(&self) -> DOMString { + self.supportsrule.read().to_css_string().into() + } +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 4f94ac8309f..90b4dc5a730 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -240,6 +240,7 @@ pub mod console; mod create; pub mod crypto; pub mod css; +pub mod cssconditionrule; pub mod cssfontfacerule; pub mod cssgroupingrule; pub mod cssimportrule; @@ -252,6 +253,7 @@ pub mod cssrulelist; pub mod cssstyledeclaration; pub mod cssstylerule; pub mod cssstylesheet; +pub mod csssupportsrule; pub mod cssviewportrule; pub mod customevent; pub mod dedicatedworkerglobalscope; diff --git a/components/script/dom/webidls/CSSConditionRule.webidl b/components/script/dom/webidls/CSSConditionRule.webidl new file mode 100644 index 00000000000..889153a085e --- /dev/null +++ b/components/script/dom/webidls/CSSConditionRule.webidl @@ -0,0 +1,9 @@ +/* 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-conditional/#cssconditionrule +[Abstract, Exposed=Window] +interface CSSConditionRule : CSSGroupingRule { + attribute DOMString conditionText; +}; diff --git a/components/script/dom/webidls/CSSMediaRule.webidl b/components/script/dom/webidls/CSSMediaRule.webidl index 9ed133fb065..0f44c382620 100644 --- a/components/script/dom/webidls/CSSMediaRule.webidl +++ b/components/script/dom/webidls/CSSMediaRule.webidl @@ -3,7 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://drafts.csswg.org/cssom/#the-cssmediarule-interface +// https://drafts.csswg.org/css-conditional/#cssmediarule [Exposed=Window] -interface CSSMediaRule : CSSGroupingRule { +interface CSSMediaRule : CSSConditionRule { [SameObject, PutForwards=mediaText] readonly attribute MediaList media; }; diff --git a/components/script/dom/webidls/CSSRule.webidl b/components/script/dom/webidls/CSSRule.webidl index cda06ab1254..d36111b0cc0 100644 --- a/components/script/dom/webidls/CSSRule.webidl +++ b/components/script/dom/webidls/CSSRule.webidl @@ -31,3 +31,7 @@ partial interface CSSRule { const unsigned short VIEWPORT_RULE = 15; }; +// https://drafts.csswg.org/css-conditional-3/#extentions-to-cssrule-interface +partial interface CSSRule { + const unsigned short SUPPORTS_RULE = 12; +}; diff --git a/components/script/dom/webidls/CSSSupportsRule.webidl b/components/script/dom/webidls/CSSSupportsRule.webidl new file mode 100644 index 00000000000..73f147c6181 --- /dev/null +++ b/components/script/dom/webidls/CSSSupportsRule.webidl @@ -0,0 +1,8 @@ +/* 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-conditional/#csssupportsrule +[Exposed=Window] +interface CSSSupportsRule : CSSConditionRule { +}; diff --git a/components/style/parser.rs b/components/style/parser.rs index d1e37ce4527..60efcb8a4be 100644 --- a/components/style/parser.rs +++ b/components/style/parser.rs @@ -11,7 +11,7 @@ use error_reporting::ParseErrorReporter; #[cfg(feature = "gecko")] use gecko_bindings::sugar::refptr::{GeckoArcPrincipal, GeckoArcURI}; use servo_url::ServoUrl; -use stylesheets::Origin; +use stylesheets::{MemoryHoleReporter, Origin}; /// Extra data that the style backend may need to parse stylesheets. #[cfg(not(feature = "gecko"))] @@ -78,6 +78,11 @@ impl<'a> ParserContext<'a> { let extra_data = ParserContextExtraData::default(); Self::new_with_extra_data(stylesheet_origin, base_url, error_reporter, extra_data) } + + /// Create a parser context for on-the-fly parsing in CSSOM + pub fn new_for_cssom(base_url: &'a ServoUrl) -> ParserContext<'a> { + Self::new(Origin::User, base_url, Box::new(MemoryHoleReporter)) + } } /// Defaults to a no-op. diff --git a/components/url/lib.rs b/components/url/lib.rs index 575baebe6e0..2a3069ff36b 100644 --- a/components/url/lib.rs +++ b/components/url/lib.rs @@ -185,3 +185,9 @@ impl Index> for ServoUrl { &self.0[range] } } + +impl From for ServoUrl { + fn from(url: Url) -> Self { + ServoUrl::from_url(url) + } +}