servo: Merge #14340 - implement StyleSheet.disabled (from heycam:sheet-disabled); r=Manishearth
authorCameron McCormack <cam@mcc.id.au>
Thu, 24 Nov 2016 20:40:24 -0800
changeset 340221 3d7fba3f53fd3b2ba1fa9a5cb835160720f9aaf1
parent 340220 92421ff0865165fd982558f52ed81e681fda1ad5
child 340222 06154a5beabfd57d2efde69164ec0102c8eb0bf6
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersManishearth
servo: Merge #14340 - implement StyleSheet.disabled (from heycam:sheet-disabled); r=Manishearth <!-- Please describe your changes on the following line: --> This implements the [CSSOM StyleSheet.disabled](https://drafts.csswg.org/cssom/#dom-stylesheet-disabled) IDL attribute. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: c1c3974fb2d8ca60f2837ccd7d2d3b345e440af8
servo/components/script/dom/cssstylesheet.rs
servo/components/script/dom/htmllinkelement.rs
servo/components/script/dom/htmlmetaelement.rs
servo/components/script/dom/htmlstyleelement.rs
servo/components/script/dom/stylesheet.rs
servo/components/script/dom/webidls/StyleSheet.webidl
servo/components/style/stylesheets.rs
servo/components/style/stylist.rs
servo/tests/unit/style/stylesheets.rs
--- a/servo/components/script/dom/cssstylesheet.rs
+++ b/servo/components/script/dom/cssstylesheet.rs
@@ -1,58 +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 dom::bindings::codegen::Bindings::CSSStyleSheetBinding;
 use dom::bindings::codegen::Bindings::CSSStyleSheetBinding::CSSStyleSheetMethods;
+use dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
 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, RulesSource};
+use dom::element::Element;
 use dom::stylesheet::StyleSheet;
 use dom::window::Window;
 use std::sync::Arc;
 use style::stylesheets::Stylesheet as StyleStyleSheet;
 
 #[dom_struct]
 pub struct CSSStyleSheet {
     stylesheet: StyleSheet,
+    owner: JS<Element>,
     rulelist: MutNullableHeap<JS<CSSRuleList>>,
     #[ignore_heap_size_of = "Arc"]
     style_stylesheet: Arc<StyleStyleSheet>,
 }
 
 impl CSSStyleSheet {
-    fn new_inherited(type_: DOMString, href: Option<DOMString>,
-                     title: Option<DOMString>, stylesheet: Arc<StyleStyleSheet>) -> CSSStyleSheet {
+    fn new_inherited(owner: &Element,
+                     type_: DOMString,
+                     href: Option<DOMString>,
+                     title: Option<DOMString>,
+                     stylesheet: Arc<StyleStyleSheet>) -> CSSStyleSheet {
         CSSStyleSheet {
             stylesheet: StyleSheet::new_inherited(type_, href, title),
+            owner: JS::from_ref(owner),
             rulelist: MutNullableHeap::new(None),
             style_stylesheet: stylesheet,
         }
     }
 
     #[allow(unrooted_must_root)]
-    pub fn new(window: &Window, type_: DOMString,
+    pub fn new(window: &Window,
+               owner: &Element,
+               type_: DOMString,
                href: Option<DOMString>,
                title: Option<DOMString>,
                stylesheet: Arc<StyleStyleSheet>) -> Root<CSSStyleSheet> {
-        reflect_dom_object(box CSSStyleSheet::new_inherited(type_, href, title, stylesheet),
+        reflect_dom_object(box CSSStyleSheet::new_inherited(owner, type_, href, title, stylesheet),
                            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())))
     }
+
+    pub fn disabled(&self) -> bool {
+        self.style_stylesheet.disabled()
+    }
+
+    pub fn set_disabled(&self, disabled: bool) {
+        if self.style_stylesheet.set_disabled(disabled) {
+            self.global().as_window().Document().invalidate_stylesheets();
+        }
+    }
 }
 
 impl CSSStyleSheetMethods for CSSStyleSheet {
     // https://drafts.csswg.org/cssom/#dom-cssstylesheet-cssrules
     fn CssRules(&self) -> Root<CSSRuleList> {
         // XXXManishearth check origin clean flag
         // https://github.com/servo/servo/issues/14327
         self.rulelist()
--- a/servo/components/script/dom/htmllinkelement.rs
+++ b/servo/components/script/dom/htmllinkelement.rs
@@ -89,16 +89,17 @@ impl HTMLLinkElement {
     pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
         self.stylesheet.borrow().clone()
     }
 
     pub fn get_cssom_stylesheet(&self) -> Option<Root<CSSStyleSheet>> {
         self.get_stylesheet().map(|sheet| {
             self.cssom_stylesheet.or_init(|| {
                 CSSStyleSheet::new(&window_from_node(self),
+                                   self.upcast::<Element>(),
                                    "text/css".into(),
                                    None, // todo handle location
                                    None, // todo handle title
                                    sheet)
             })
         })
     }
 }
--- a/servo/components/script/dom/htmlmetaelement.rs
+++ b/servo/components/script/dom/htmlmetaelement.rs
@@ -58,16 +58,17 @@ impl HTMLMetaElement {
     pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
         self.stylesheet.borrow().clone()
     }
 
     pub fn get_cssom_stylesheet(&self) -> Option<Root<CSSStyleSheet>> {
         self.get_stylesheet().map(|sheet| {
             self.cssom_stylesheet.or_init(|| {
                 CSSStyleSheet::new(&window_from_node(self),
+                                   self.upcast::<Element>(),
                                    "text/css".into(),
                                    None, // todo handle location
                                    None, // todo handle title
                                    sheet)
             })
         })
     }
 
@@ -98,16 +99,17 @@ impl HTMLMetaElement {
                 if let Some(translated_rule) = ViewportRule::from_meta(&**content) {
                     *self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet {
                         rules: vec![CssRule::Viewport(Arc::new(RwLock::new(translated_rule)))].into(),
                         origin: Origin::Author,
                         media: Default::default(),
                         // Viewport constraints are always recomputed on resize; they don't need to
                         // force all styles to be recomputed.
                         dirty_on_viewport_size_change: AtomicBool::new(false),
+                        disabled: AtomicBool::new(false),
                     }));
                     let doc = document_from_node(self);
                     doc.invalidate_stylesheets();
                 }
             }
         }
     }
 
--- a/servo/components/script/dom/htmlstyleelement.rs
+++ b/servo/components/script/dom/htmlstyleelement.rs
@@ -81,16 +81,17 @@ impl HTMLStyleElement {
     pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
         self.stylesheet.borrow().clone()
     }
 
     pub fn get_cssom_stylesheet(&self) -> Option<Root<CSSStyleSheet>> {
         self.get_stylesheet().map(|sheet| {
             self.cssom_stylesheet.or_init(|| {
                 CSSStyleSheet::new(&window_from_node(self),
+                                   self.upcast::<Element>(),
                                    "text/css".into(),
                                    None, // todo handle location
                                    None, // todo handle title
                                    sheet)
             })
         })
     }
 }
--- a/servo/components/script/dom/stylesheet.rs
+++ b/servo/components/script/dom/stylesheet.rs
@@ -1,36 +1,39 @@
 /* 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::StyleSheetBinding;
 use dom::bindings::codegen::Bindings::StyleSheetBinding::StyleSheetMethods;
+use dom::bindings::inheritance::Castable;
 use dom::bindings::js::Root;
 use dom::bindings::reflector::{Reflector, reflect_dom_object};
 use dom::bindings::str::DOMString;
+use dom::cssstylesheet::CSSStyleSheet;
 use dom::window::Window;
 
-
 #[dom_struct]
 pub struct StyleSheet {
     reflector_: Reflector,
     type_: DOMString,
     href: Option<DOMString>,
     title: Option<DOMString>,
 }
 
 impl StyleSheet {
     #[allow(unrooted_must_root)]
-    pub fn new_inherited(type_: DOMString, href: Option<DOMString>, title: Option<DOMString>) -> StyleSheet {
+    pub fn new_inherited(type_: DOMString,
+                         href: Option<DOMString>,
+                         title: Option<DOMString>) -> StyleSheet {
         StyleSheet {
             reflector_: Reflector::new(),
             type_: type_,
             href: href,
-            title: title
+            title: title,
         }
     }
 
     #[allow(unrooted_must_root)]
     pub fn new(window: &Window, type_: DOMString,
                href: Option<DOMString>,
                title: Option<DOMString>) -> Root<StyleSheet> {
         reflect_dom_object(box StyleSheet::new_inherited(type_, href, title),
@@ -50,10 +53,19 @@ impl StyleSheetMethods for StyleSheet {
     fn GetHref(&self) -> Option<DOMString> {
         self.href.clone()
     }
 
     // https://drafts.csswg.org/cssom/#dom-stylesheet-title
     fn GetTitle(&self) -> Option<DOMString> {
         self.title.clone()
     }
+
+    // https://drafts.csswg.org/cssom/#dom-stylesheet-disabled
+    fn Disabled(&self) -> bool {
+        self.downcast::<CSSStyleSheet>().unwrap().disabled()
+    }
+
+    // https://drafts.csswg.org/cssom/#dom-stylesheet-disabled
+    fn SetDisabled(&self, disabled: bool) {
+        self.downcast::<CSSStyleSheet>().unwrap().set_disabled(disabled)
+    }
 }
-
--- a/servo/components/script/dom/webidls/StyleSheet.webidl
+++ b/servo/components/script/dom/webidls/StyleSheet.webidl
@@ -8,16 +8,16 @@ interface StyleSheet {
   readonly attribute DOMString type_;
   readonly attribute DOMString? href;
 
   // readonly attribute (Element or ProcessingInstruction)? ownerNode;
   // readonly attribute StyleSheet? parentStyleSheet;
   readonly attribute DOMString? title;
 
   // [SameObject, PutForwards=mediaText] readonly attribute MediaList media;
-  // attribute boolean disabled;
+  attribute boolean disabled;
 };
 
 // https://drafts.csswg.org/cssom/#the-linkstyle-interface
 [NoInterfaceObject]
 interface LinkStyle {
   readonly attribute StyleSheet? sheet;
 };
--- a/servo/components/style/stylesheets.rs
+++ b/servo/components/style/stylesheets.rs
@@ -108,16 +108,17 @@ impl CssRules {
 pub struct Stylesheet {
     /// List of rules in the order they were found (important for
     /// cascading order)
     pub rules: CssRules,
     /// List of media associated with the Stylesheet.
     pub media: Arc<RwLock<MediaList>>,
     pub origin: Origin,
     pub dirty_on_viewport_size_change: AtomicBool,
+    pub disabled: AtomicBool,
 }
 
 
 /// This structure holds the user-agent and user stylesheets.
 pub struct UserAgentStylesheets {
     pub user_or_user_agent_stylesheets: Vec<Stylesheet>,
     pub quirks_mode_stylesheet: Stylesheet,
 }
@@ -397,16 +398,17 @@ impl Stylesheet {
             }
         }
 
         Stylesheet {
             origin: origin,
             rules: rules.into(),
             media: Arc::new(RwLock::new(media)),
             dirty_on_viewport_size_change: AtomicBool::new(input.seen_viewport_percentages()),
+            disabled: AtomicBool::new(false),
         }
     }
 
     pub fn dirty_on_viewport_size_change(&self) -> bool {
         self.dirty_on_viewport_size_change.load(Ordering::SeqCst)
     }
 
     /// When CSSOM inserts a rule or declaration into this stylesheet, it needs to call this method
@@ -437,16 +439,30 @@ impl Stylesheet {
     ///
     /// If a condition does not hold, its associated conditional group rule and
     /// nested rules will be skipped. Use `rules` if all rules need to be
     /// examined.
     #[inline]
     pub fn effective_rules<F>(&self, device: &Device, mut f: F) where F: FnMut(&CssRule) {
         effective_rules(&self.rules.0.read(), device, &mut f);
     }
+
+    /// Returns whether the stylesheet has been explicitly disabled through the CSSOM.
+    pub fn disabled(&self) -> bool {
+        self.disabled.load(Ordering::SeqCst)
+    }
+
+    /// Records that the stylesheet has been explicitly disabled through the CSSOM.
+    /// Returns whether the the call resulted in a change in disabled state.
+    ///
+    /// Disabled stylesheets remain in the document, but their rules are not added to
+    /// the Stylist.
+    pub fn set_disabled(&self, disabled: bool) -> bool {
+        self.disabled.swap(disabled, Ordering::SeqCst) != disabled
+    }
 }
 
 fn effective_rules<F>(rules: &[CssRule], device: &Device, f: &mut F) where F: FnMut(&CssRule) {
     for rule in rules {
         f(rule);
         rule.with_nested_rules_and_mq(|rules, mq| {
             if let Some(media_queries) = mq {
                 if !media_queries.evaluate(device) {
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -164,17 +164,17 @@ impl Stylist {
             self.add_stylesheet(stylesheet);
         }
 
         self.is_device_dirty = false;
         true
     }
 
     fn add_stylesheet(&mut self, stylesheet: &Stylesheet) {
-        if !stylesheet.is_effective_for_device(&self.device) {
+        if stylesheet.disabled() || !stylesheet.is_effective_for_device(&self.device) {
             return;
         }
 
         // Work around borrowing all of `self` if `self.something` is used in it
         // instead of just `self.something`
         macro_rules! borrow_self_field {
             ($($x: ident),+) => {
                 $(
--- a/servo/tests/unit/style/stylesheets.rs
+++ b/servo/tests/unit/style/stylesheets.rs
@@ -52,16 +52,17 @@ fn test_parse_stylesheet() {
     let url = ServoUrl::parse("about::test").unwrap();
     let stylesheet = Stylesheet::from_str(css, url, Origin::UserAgent, Default::default(),
                                           Box::new(CSSErrorReporterTest),
                                           ParserContextExtraData::default());
     let expected = Stylesheet {
         origin: Origin::UserAgent,
         media: Default::default(),
         dirty_on_viewport_size_change: AtomicBool::new(false),
+        disabled: AtomicBool::new(false),
         rules: vec![
             CssRule::Namespace(Arc::new(RwLock::new(NamespaceRule {
                 prefix: None,
                 url: NsAtom::from("http://www.w3.org/1999/xhtml")
             }))),
             CssRule::Style(Arc::new(RwLock::new(StyleRule {
                 selectors: SelectorList(vec![
                     Selector {