style: Move cached media query results into per-origin data. draft
authorCameron McCormack <cam@mcc.id.au>
Sat, 12 Aug 2017 15:46:57 +0800
changeset 645503 a836c44f16e1943798fb004b574cf9f50dc31809
parent 645502 54c50d92422855bf9d16156f3e82b4daf3a9b8bf
child 645504 4a22de18573814dd70ad97ebeecceb800e37f44c
push id73769
push userbmo:cam@mcc.id.au
push dateSun, 13 Aug 2017 04:04:30 +0000
milestone57.0a1
style: Move cached media query results into per-origin data. MozReview-Commit-ID: 7rtQ7NPrH7p
servo/components/style/invalidation/media_queries.rs
servo/components/style/stylist.rs
--- a/servo/components/style/invalidation/media_queries.rs
+++ b/servo/components/style/invalidation/media_queries.rs
@@ -47,16 +47,17 @@ pub trait ToMediaListKey : Sized {
 }
 
 impl ToMediaListKey for Stylesheet {}
 impl ToMediaListKey for ImportRule {}
 impl ToMediaListKey for MediaRule {}
 
 /// A struct that holds the result of a media query evaluation pass for the
 /// media queries that evaluated successfully.
+#[derive(Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub struct EffectiveMediaQueryResults {
     /// The set of media lists that matched last time.
     set: FnvHashSet<MediaListKey>,
 }
 
 impl EffectiveMediaQueryResults {
     /// Trivially constructs an empty `EffectiveMediaQueryResults`.
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -69,19 +69,16 @@ pub struct Stylist {
     /// On Servo, on the other hand, the device is a really cheap representation
     /// that is recreated each time some constraint changes and calling
     /// `set_device`.
     device: Device,
 
     /// Viewport constraints based on the current device.
     viewport_constraints: Option<ViewportConstraints>,
 
-    /// Effective media query results cached from the last rebuild.
-    effective_media_query_results: EffectiveMediaQueryResults,
-
     /// If true, the quirks-mode stylesheet is applied.
     #[cfg_attr(feature = "servo", ignore_heap_size_of = "defined in selectors")]
     quirks_mode: QuirksMode,
 
     /// If true, the device has changed, and the stylist needs to be updated.
     is_device_dirty: bool,
 
     /// If true, the stylist is in a cleared state (e.g. just-constructed, or
@@ -139,17 +136,16 @@ impl Stylist {
     #[inline]
     pub fn new(device: Device, quirks_mode: QuirksMode) -> Self {
         Stylist {
             viewport_constraints: None,
             device: device,
             is_device_dirty: true,
             is_cleared: true,
             quirks_mode: quirks_mode,
-            effective_media_query_results: EffectiveMediaQueryResults::new(),
 
             cascade_data: Default::default(),
             precomputed_pseudo_element_decls: PerPseudoElementMap::default(),
             rules_source_order: 0,
             rule_tree: RuleTree::new(),
             num_rebuilds: 0,
         }
 
@@ -210,17 +206,16 @@ impl Stylist {
     /// Stylist::new.
     pub fn clear(&mut self) {
         if self.is_cleared {
             return
         }
 
         self.is_cleared = true;
 
-        self.effective_media_query_results.clear();
         self.viewport_constraints = None;
         // preserve current device
         self.is_device_dirty = true;
         // preserve current quirks_mode value
         self.cascade_data.clear();
         self.precomputed_pseudo_element_decls.clear();
         self.rules_source_order = 0;
         // We want to keep rule_tree around across stylist rebuilds.
@@ -348,23 +343,24 @@ impl Stylist {
     where
         S: StylesheetInDocument + ToMediaListKey + 'static,
     {
         if !stylesheet.enabled() ||
            !stylesheet.is_effective_for_device(&self.device, guard) {
             return;
         }
 
-        self.effective_media_query_results.saw_effective(stylesheet);
-
         let origin = stylesheet.origin(guard);
-
         let origin_cascade_data =
             self.cascade_data.borrow_mut_for_origin(&origin);
 
+        origin_cascade_data
+            .effective_media_query_results
+            .saw_effective(stylesheet);
+
         for rule in stylesheet.effective_rules(&self.device, guard) {
             match *rule {
                 CssRule::Style(ref locked) => {
                     let style_rule = locked.read_with(&guard);
                     origin_cascade_data.num_declarations +=
                         style_rule.block.read_with(&guard).len();
                     for selector in &style_rule.selectors.0 {
                         origin_cascade_data.num_selectors += 1;
@@ -431,24 +427,28 @@ impl Stylist {
                                 RevalidationSelectorAndHashes::new(selector.clone(), hashes),
                                 self.quirks_mode);
                         }
                     }
                     self.rules_source_order += 1;
                 }
                 CssRule::Import(ref lock) => {
                     let import_rule = lock.read_with(guard);
-                    self.effective_media_query_results.saw_effective(import_rule);
+                    origin_cascade_data
+                        .effective_media_query_results
+                        .saw_effective(import_rule);
 
                     // NOTE: effective_rules visits the inner stylesheet if
                     // appropriate.
                 }
                 CssRule::Media(ref lock) => {
                     let media_rule = lock.read_with(guard);
-                    self.effective_media_query_results.saw_effective(media_rule);
+                    origin_cascade_data
+                        .effective_media_query_results
+                        .saw_effective(media_rule);
                 }
                 CssRule::Keyframes(ref keyframes_rule) => {
                     let keyframes_rule = keyframes_rule.read_with(guard);
                     debug!("Found valid keyframes rule: {:?}", *keyframes_rule);
 
                     // Don't let a prefixed keyframes animation override a non-prefixed one.
                     let needs_insertion =
                         keyframes_rule.vendor_prefix.is_none() ||
@@ -949,18 +949,24 @@ impl Stylist {
         use invalidation::media_queries::PotentiallyEffectiveMediaRules;
 
         debug!("Stylist::media_features_change_changed_style");
 
         for stylesheet in stylesheets {
             let effective_now =
                 stylesheet.is_effective_for_device(&self.device, guard);
 
+            let origin = stylesheet.origin(guard);
+            let origin_cascade_data =
+                self.cascade_data.borrow_for_origin(&origin);
+
             let effective_then =
-                self.effective_media_query_results.was_effective(stylesheet);
+                origin_cascade_data
+                    .effective_media_query_results
+                    .was_effective(stylesheet);
 
             if effective_now != effective_then {
                 debug!(" > Stylesheet changed -> {}, {}",
                        effective_then, effective_now);
                 return true
             }
 
             if !effective_now {
@@ -989,34 +995,38 @@ impl Stylist {
                         continue;
                     }
                     CssRule::Import(ref lock) => {
                         let import_rule = lock.read_with(guard);
                         let effective_now =
                             import_rule.stylesheet
                                 .is_effective_for_device(&self.device, guard);
                         let effective_then =
-                            self.effective_media_query_results.was_effective(import_rule);
+                            origin_cascade_data
+                                .effective_media_query_results
+                                .was_effective(import_rule);
                         if effective_now != effective_then {
                             debug!(" > @import rule changed {} -> {}",
                                    effective_then, effective_now);
                             return true;
                         }
 
                         if !effective_now {
                             iter.skip_children();
                         }
                     }
                     CssRule::Media(ref lock) => {
                         let media_rule = lock.read_with(guard);
                         let mq = media_rule.media_queries.read_with(guard);
                         let effective_now =
                             mq.evaluate(&self.device, self.quirks_mode);
                         let effective_then =
-                            self.effective_media_query_results.was_effective(media_rule);
+                            origin_cascade_data
+                                .effective_media_query_results
+                                .was_effective(media_rule);
                         if effective_now != effective_then {
                             debug!(" > @media rule changed {} -> {}",
                                    effective_then, effective_now);
                             return true;
                         }
 
                         if !effective_now {
                             iter.skip_children();
@@ -1607,16 +1617,19 @@ struct CascadeData {
     mapped_ids: NonCountingBloomFilter,
 
     /// Selectors that require explicit cache revalidation (i.e. which depend
     /// on state that is not otherwise visible to the cache, like attributes or
     /// tree-structural state like child index and pseudos).
     #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")]
     selectors_for_cache_revalidation: SelectorMap<RevalidationSelectorAndHashes>,
 
+    /// Effective media query results cached from the last rebuild.
+    effective_media_query_results: EffectiveMediaQueryResults,
+
     /// The total number of selectors.
     num_selectors: usize,
 
     /// The total number of declarations.
     num_declarations: usize,
 }
 
 impl CascadeData {
@@ -1626,16 +1639,17 @@ impl CascadeData {
             pseudos_map: PerPseudoElementMap::default(),
             animations: Default::default(),
             invalidation_map: InvalidationMap::new(),
             attribute_dependencies: NonCountingBloomFilter::new(),
             style_attribute_dependency: false,
             state_dependencies: ElementState::empty(),
             mapped_ids: NonCountingBloomFilter::new(),
             selectors_for_cache_revalidation: SelectorMap::new(),
+            effective_media_query_results: EffectiveMediaQueryResults::new(),
             num_selectors: 0,
             num_declarations: 0,
         }
     }
 
     #[inline]
     fn borrow_for_pseudo(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
         match pseudo {
@@ -1655,16 +1669,17 @@ impl PerOriginClear for CascadeData {
         self.pseudos_map = Default::default();
         self.animations = Default::default();
         self.invalidation_map.clear();
         self.attribute_dependencies.clear();
         self.style_attribute_dependency = false;
         self.state_dependencies = ElementState::empty();
         self.mapped_ids.clear();
         self.selectors_for_cache_revalidation = SelectorMap::new();
+        self.effective_media_query_results.clear();
         self.num_selectors = 0;
         self.num_declarations = 0;
     }
 }
 
 impl Default for CascadeData {
     fn default() -> Self {
         CascadeData::new()