diff --git a/components/style/rule_collector.rs b/components/style/rule_collector.rs index 6424cc237db..6304a1af2d7 100644 --- a/components/style/rule_collector.rs +++ b/components/style/rule_collector.rs @@ -5,7 +5,7 @@ //! Collects a series of applicable rules for a given element. use crate::applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList}; -use crate::dom::{TElement, TShadowRoot}; +use crate::dom::{TElement, TNode, TShadowRoot}; use crate::properties::{AnimationRules, PropertyDeclarationBlock}; use crate::rule_tree::{CascadeLevel, ShadowCascadeOrder}; use crate::selector_map::SelectorMap; @@ -17,6 +17,43 @@ use selectors::matching::{ElementSelectorFlags, MatchingContext}; use servo_arc::ArcBorrow; use smallvec::SmallVec; +/// This is a bit of a hack so matches the rules of the enclosing +/// tree. +/// +/// This function returns the containing shadow host ignoring shadow +/// trees, since those match the enclosing tree's rules. +/// +/// Only a handful of places need to really care about this. This is not a +/// problem for invalidation and that kind of stuff because they still don't +/// match rules based on elements outside of the shadow tree, and because the +/// subtrees are immutable and recreated each time the source tree +/// changes. +/// +/// We historically allow cross-document to have these rules applied, +/// but I think that's not great. Gecko is the only engine supporting that. +/// +/// See https://github.com/w3c/svgwg/issues/504 for the relevant spec +/// discussion. +#[inline] +pub fn containing_shadow_ignoring_svg_use( + element: E, +) -> Option<::ConcreteShadowRoot> { + let mut shadow = element.containing_shadow()?; + loop { + let host = shadow.host(); + let host_is_svg_use_element = + host.is_svg_element() && host.local_name() == &*local_name!("use"); + if !host_is_svg_use_element { + return Some(shadow); + } + debug_assert!( + shadow.style_data().is_none(), + "We allow no stylesheets in subtrees" + ); + shadow = host.containing_shadow()?; + } +} + /// An object that we use with all the intermediate state needed for the /// cascade. /// @@ -213,43 +250,19 @@ where return; } - let mut current_containing_shadow = self.rule_hash_target.containing_shadow(); - while let Some(containing_shadow) = current_containing_shadow { - let cascade_data = containing_shadow.style_data(); - let host = containing_shadow.host(); - if let Some(map) = cascade_data.and_then(|data| data.normal_rules(self.pseudo_element)) - { - self.collect_rules_in_shadow_tree(host, map, CascadeLevel::SameTreeAuthorNormal); - } - let host_is_svg_use_element = - host.is_svg_element() && host.local_name() == &*local_name!("use"); - if !host_is_svg_use_element { - self.matches_document_author_rules = false; - break; - } + let containing_shadow = containing_shadow_ignoring_svg_use(self.rule_hash_target); + let containing_shadow = match containing_shadow { + Some(s) => s, + None => return, + }; - debug_assert!( - cascade_data.is_none(), - "We allow no stylesheets in subtrees" - ); + self.matches_document_author_rules = false; - // NOTE(emilio): Hack so matches the rules of the - // enclosing tree. - // - // This is not a problem for invalidation and that kind of stuff - // because they still don't match rules based on elements - // outside of the shadow tree, and because the - // subtrees are immutable and recreated each time the source - // tree changes. - // - // We historically allow cross-document to have these - // rules applied, but I think that's not great. Gecko is the - // only engine supporting that. - // - // See https://github.com/w3c/svgwg/issues/504 for the relevant - // spec discussion. - current_containing_shadow = host.containing_shadow(); - self.matches_document_author_rules = current_containing_shadow.is_none(); + let cascade_data = containing_shadow.style_data(); + let host = containing_shadow.host(); + if let Some(map) = cascade_data.and_then(|data| data.normal_rules(self.pseudo_element)) + { + self.collect_rules_in_shadow_tree(host, map, CascadeLevel::SameTreeAuthorNormal); } } diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 592e4e81081..3815a8a3da6 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -17,7 +17,7 @@ use crate::media_queries::Device; use crate::properties::{self, CascadeMode, ComputedValues}; use crate::properties::{AnimationRules, PropertyDeclarationBlock}; use crate::rule_cache::{RuleCache, RuleCacheConditions}; -use crate::rule_collector::RuleCollector; +use crate::rule_collector::{RuleCollector, containing_shadow_ignoring_svg_use}; use crate::rule_tree::{CascadeLevel, RuleTree, ShadowCascadeOrder, StrongRuleNode, StyleSource}; use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, SelectorMapEntry}; use crate::selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap}; @@ -1187,7 +1187,9 @@ impl Stylist { } } - if let Some(shadow) = element.containing_shadow() { + // Use the same rules to look for the containing host as we do for rule + // collection. + if let Some(shadow) = containing_shadow_ignoring_svg_use(element) { if let Some(data) = shadow.style_data() { try_find_in!(data); }