Bug 1728754 - Factor out adding a rule in CascadeData::add_rule. r=boris
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sat, 04 Sep 2021 07:42:45 +0000
changeset 591013 743777e6d2f275281a0e519ef226a07acad4f746
parent 591011 ff8d4b53a61249dce1b7c6e77c87e156ea9610fc
child 591014 56c800f59664d6e5a811fd3f959af66e574336cd
push id38762
push userccozmuta@mozilla.com
push dateSat, 04 Sep 2021 21:51:48 +0000
treeherdermozilla-central@1546185c8149 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersboris
bugs1728754
milestone93.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1728754 - Factor out adding a rule in CascadeData::add_rule. r=boris This shouldn't have any behavior change, but is necessary because for cascade layers we are going to need to handle the child rules / sheets ourselves, in order to handle nested layers properly. Differential Revision: https://phabricator.services.mozilla.com/D124334
servo/components/style/stylist.rs
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -2145,16 +2145,189 @@ impl CascadeData {
                     debug!(" + {:?}", media_rule.media_queries.read_with(guard));
                     results.push(media_rule.to_media_list_key());
                 },
                 _ => {},
             }
         }
     }
 
+    #[inline]
+    fn add_rule<S>(
+        &mut self,
+        rule: &CssRule,
+        _device: &Device,
+        quirks_mode: QuirksMode,
+        stylesheet: &S,
+        guard: &SharedRwLockReadGuard,
+        rebuild_kind: SheetRebuildKind,
+        mut precomputed_pseudo_element_decls: Option<&mut PrecomputedPseudoElementDeclarations>,
+    ) -> Result<(), FailedAllocationError>
+    where
+        S: StylesheetInDocument + 'static,
+    {
+        match *rule {
+            CssRule::Style(ref locked) => {
+                let style_rule = locked.read_with(&guard);
+                self.num_declarations += style_rule.block.read_with(&guard).len();
+                for selector in &style_rule.selectors.0 {
+                    self.num_selectors += 1;
+
+                    let pseudo_element = selector.pseudo_element();
+
+                    if let Some(pseudo) = pseudo_element {
+                        if pseudo.is_precomputed() {
+                            debug_assert!(selector.is_universal());
+                            debug_assert_eq!(stylesheet.contents().origin, Origin::UserAgent);
+
+                            precomputed_pseudo_element_decls
+                                .as_mut()
+                                .expect("Expected precomputed declarations for the UA level")
+                                .get_or_insert_with(pseudo, Vec::new)
+                                .push(ApplicableDeclarationBlock::new(
+                                    StyleSource::from_rule(locked.clone()),
+                                    self.rules_source_order,
+                                    CascadeLevel::UANormal,
+                                    selector.specificity(),
+                                ));
+                            continue;
+                        }
+                        if pseudo.is_unknown_webkit_pseudo_element() {
+                            continue;
+                        }
+                    }
+
+                    let hashes = AncestorHashes::new(&selector, quirks_mode);
+
+                    let rule = Rule::new(
+                        selector.clone(),
+                        hashes,
+                        locked.clone(),
+                        self.rules_source_order,
+                    );
+
+                    if rebuild_kind.should_rebuild_invalidation() {
+                        self.invalidation_map.note_selector(selector, quirks_mode)?;
+                        let mut needs_revalidation = false;
+                        let mut visitor = StylistSelectorVisitor {
+                            needs_revalidation: &mut needs_revalidation,
+                            passed_rightmost_selector: false,
+                            attribute_dependencies: &mut self.attribute_dependencies,
+                            state_dependencies: &mut self.state_dependencies,
+                            document_state_dependencies: &mut self.document_state_dependencies,
+                            mapped_ids: &mut self.mapped_ids,
+                        };
+
+                        rule.selector.visit(&mut visitor);
+
+                        if needs_revalidation {
+                            self.selectors_for_cache_revalidation.insert(
+                                RevalidationSelectorAndHashes::new(
+                                    rule.selector.clone(),
+                                    rule.hashes.clone(),
+                                ),
+                                quirks_mode,
+                            )?;
+                        }
+                    }
+
+                    // Part is special, since given it doesn't have any
+                    // selectors inside, it's not worth using a whole
+                    // SelectorMap for it.
+                    if let Some(parts) = selector.parts() {
+                        // ::part() has all semantics, so we just need to
+                        // put any of them in the selector map.
+                        //
+                        // We choose the last one quite arbitrarily,
+                        // expecting it's slightly more likely to be more
+                        // specific.
+                        self.part_rules
+                            .get_or_insert_with(|| Box::new(Default::default()))
+                            .for_insertion(pseudo_element)
+                            .try_entry(parts.last().unwrap().clone().0)?
+                            .or_insert_with(SmallVec::new)
+                            .try_push(rule)?;
+                    } else {
+                        // NOTE(emilio): It's fine to look at :host and then at
+                        // ::slotted(..), since :host::slotted(..) could never
+                        // possibly match, as <slot> is not a valid shadow host.
+                        let rules =
+                            if selector.is_featureless_host_selector_or_pseudo_element() {
+                                self.host_rules
+                                    .get_or_insert_with(|| Box::new(Default::default()))
+                            } else if selector.is_slotted() {
+                                self.slotted_rules
+                                    .get_or_insert_with(|| Box::new(Default::default()))
+                            } else {
+                                &mut self.normal_rules
+                            }
+                            .for_insertion(pseudo_element);
+                        rules.insert(rule, quirks_mode)?;
+                    }
+                }
+                self.rules_source_order += 1;
+            },
+            CssRule::Import(ref lock) => {
+                if rebuild_kind.should_rebuild_invalidation() {
+                    let import_rule = lock.read_with(guard);
+                    self.effective_media_query_results
+                        .saw_effective(import_rule);
+                }
+
+                // NOTE: effective_rules visits the inner stylesheet if
+                // appropriate.
+            },
+            CssRule::Media(ref lock) => {
+                if rebuild_kind.should_rebuild_invalidation() {
+                    let media_rule = lock.read_with(guard);
+                    self.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() ||
+                    self.animations
+                        .get(keyframes_rule.name.as_atom())
+                        .map_or(true, |rule| rule.vendor_prefix.is_some());
+                if needs_insertion {
+                    let animation = KeyframesAnimation::from_keyframes(
+                        &keyframes_rule.keyframes,
+                        keyframes_rule.vendor_prefix.clone(),
+                        guard,
+                    );
+                    debug!("Found valid keyframe animation: {:?}", animation);
+                    self.animations
+                        .try_insert(keyframes_rule.name.as_atom().clone(), animation)?;
+                }
+            },
+            #[cfg(feature = "gecko")]
+            CssRule::FontFace(ref rule) => {
+                self.extra_data.add_font_face(rule);
+            },
+            #[cfg(feature = "gecko")]
+            CssRule::FontFeatureValues(ref rule) => {
+                self.extra_data.add_font_feature_values(rule);
+            },
+            #[cfg(feature = "gecko")]
+            CssRule::CounterStyle(ref rule) => {
+                self.extra_data.add_counter_style(guard, rule);
+            },
+            #[cfg(feature = "gecko")]
+            CssRule::Page(ref rule) => {
+                self.extra_data.add_page(rule);
+            },
+            // We don't care about any other rule.
+            _ => {},
+        }
+        Ok(())
+    }
+
     // Returns Err(..) to signify OOM
     fn add_stylesheet<S>(
         &mut self,
         device: &Device,
         quirks_mode: QuirksMode,
         stylesheet: &S,
         guard: &SharedRwLockReadGuard,
         rebuild_kind: SheetRebuildKind,
@@ -2163,179 +2336,32 @@ impl CascadeData {
     where
         S: StylesheetInDocument + 'static,
     {
         if !stylesheet.enabled() || !stylesheet.is_effective_for_device(device, guard) {
             return Ok(());
         }
 
         let contents = stylesheet.contents();
-        let origin = contents.origin;
 
         if rebuild_kind.should_rebuild_invalidation() {
             self.effective_media_query_results.saw_effective(contents);
         }
 
+
         for rule in stylesheet.effective_rules(device, guard) {
-            match *rule {
-                CssRule::Style(ref locked) => {
-                    let style_rule = locked.read_with(&guard);
-                    self.num_declarations += style_rule.block.read_with(&guard).len();
-                    for selector in &style_rule.selectors.0 {
-                        self.num_selectors += 1;
-
-                        let pseudo_element = selector.pseudo_element();
-
-                        if let Some(pseudo) = pseudo_element {
-                            if pseudo.is_precomputed() {
-                                debug_assert!(selector.is_universal());
-                                debug_assert!(matches!(origin, Origin::UserAgent));
-
-                                precomputed_pseudo_element_decls
-                                    .as_mut()
-                                    .expect("Expected precomputed declarations for the UA level")
-                                    .get_or_insert_with(pseudo, Vec::new)
-                                    .push(ApplicableDeclarationBlock::new(
-                                        StyleSource::from_rule(locked.clone()),
-                                        self.rules_source_order,
-                                        CascadeLevel::UANormal,
-                                        selector.specificity(),
-                                    ));
-                                continue;
-                            }
-                            if pseudo.is_unknown_webkit_pseudo_element() {
-                                continue;
-                            }
-                        }
-
-                        let hashes = AncestorHashes::new(&selector, quirks_mode);
-
-                        let rule = Rule::new(
-                            selector.clone(),
-                            hashes,
-                            locked.clone(),
-                            self.rules_source_order,
-                        );
-
-                        if rebuild_kind.should_rebuild_invalidation() {
-                            self.invalidation_map.note_selector(selector, quirks_mode)?;
-                            let mut needs_revalidation = false;
-                            let mut visitor = StylistSelectorVisitor {
-                                needs_revalidation: &mut needs_revalidation,
-                                passed_rightmost_selector: false,
-                                attribute_dependencies: &mut self.attribute_dependencies,
-                                state_dependencies: &mut self.state_dependencies,
-                                document_state_dependencies: &mut self.document_state_dependencies,
-                                mapped_ids: &mut self.mapped_ids,
-                            };
-
-                            rule.selector.visit(&mut visitor);
-
-                            if needs_revalidation {
-                                self.selectors_for_cache_revalidation.insert(
-                                    RevalidationSelectorAndHashes::new(
-                                        rule.selector.clone(),
-                                        rule.hashes.clone(),
-                                    ),
-                                    quirks_mode,
-                                )?;
-                            }
-                        }
-
-                        // Part is special, since given it doesn't have any
-                        // selectors inside, it's not worth using a whole
-                        // SelectorMap for it.
-                        if let Some(parts) = selector.parts() {
-                            // ::part() has all semantics, so we just need to
-                            // put any of them in the selector map.
-                            //
-                            // We choose the last one quite arbitrarily,
-                            // expecting it's slightly more likely to be more
-                            // specific.
-                            self.part_rules
-                                .get_or_insert_with(|| Box::new(Default::default()))
-                                .for_insertion(pseudo_element)
-                                .try_entry(parts.last().unwrap().clone().0)?
-                                .or_insert_with(SmallVec::new)
-                                .try_push(rule)?;
-                        } else {
-                            // NOTE(emilio): It's fine to look at :host and then at
-                            // ::slotted(..), since :host::slotted(..) could never
-                            // possibly match, as <slot> is not a valid shadow host.
-                            let rules =
-                                if selector.is_featureless_host_selector_or_pseudo_element() {
-                                    self.host_rules
-                                        .get_or_insert_with(|| Box::new(Default::default()))
-                                } else if selector.is_slotted() {
-                                    self.slotted_rules
-                                        .get_or_insert_with(|| Box::new(Default::default()))
-                                } else {
-                                    &mut self.normal_rules
-                                }
-                                .for_insertion(pseudo_element);
-                            rules.insert(rule, quirks_mode)?;
-                        }
-                    }
-                    self.rules_source_order += 1;
-                },
-                CssRule::Import(ref lock) => {
-                    if rebuild_kind.should_rebuild_invalidation() {
-                        let import_rule = lock.read_with(guard);
-                        self.effective_media_query_results
-                            .saw_effective(import_rule);
-                    }
-
-                    // NOTE: effective_rules visits the inner stylesheet if
-                    // appropriate.
-                },
-                CssRule::Media(ref lock) => {
-                    if rebuild_kind.should_rebuild_invalidation() {
-                        let media_rule = lock.read_with(guard);
-                        self.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() ||
-                        self.animations
-                            .get(keyframes_rule.name.as_atom())
-                            .map_or(true, |rule| rule.vendor_prefix.is_some());
-                    if needs_insertion {
-                        let animation = KeyframesAnimation::from_keyframes(
-                            &keyframes_rule.keyframes,
-                            keyframes_rule.vendor_prefix.clone(),
-                            guard,
-                        );
-                        debug!("Found valid keyframe animation: {:?}", animation);
-                        self.animations
-                            .try_insert(keyframes_rule.name.as_atom().clone(), animation)?;
-                    }
-                },
-                #[cfg(feature = "gecko")]
-                CssRule::FontFace(ref rule) => {
-                    self.extra_data.add_font_face(rule);
-                },
-                #[cfg(feature = "gecko")]
-                CssRule::FontFeatureValues(ref rule) => {
-                    self.extra_data.add_font_feature_values(rule);
-                },
-                #[cfg(feature = "gecko")]
-                CssRule::CounterStyle(ref rule) => {
-                    self.extra_data.add_counter_style(guard, rule);
-                },
-                #[cfg(feature = "gecko")]
-                CssRule::Page(ref rule) => {
-                    self.extra_data.add_page(rule);
-                },
-                // We don't care about any other rule.
-                _ => {},
-            }
+            self.add_rule(
+                rule,
+                device,
+                quirks_mode,
+                stylesheet,
+                guard,
+                rebuild_kind,
+                precomputed_pseudo_element_decls.as_deref_mut(),
+            )?;
         }
 
         Ok(())
     }
 
     /// Returns whether all the media-feature affected values matched before and
     /// match now in the given stylesheet.
     pub fn media_feature_affected_matches<S>(