mirror of
https://github.com/servo/servo.git
synced 2025-07-03 05:23:38 +01:00
style: Make <use> shadow trees lookup keyframe rules in the containing tree.
The same thing we do for rule matching. Differential Revision: https://phabricator.services.mozilla.com/D14548
This commit is contained in:
parent
31838b1e6f
commit
b59ec2e699
2 changed files with 53 additions and 38 deletions
|
@ -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 <svg:use> matches the rules of the enclosing
|
||||
/// tree.
|
||||
///
|
||||
/// This function returns the containing shadow host ignoring <svg:use> 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
|
||||
/// <svg:use> subtrees are immutable and recreated each time the source tree
|
||||
/// changes.
|
||||
///
|
||||
/// We historically allow cross-document <svg:use> 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<E: TElement>(
|
||||
element: E,
|
||||
) -> Option<<E::ConcreteNode as TNode>::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 <svg:use> subtrees"
|
||||
);
|
||||
shadow = host.containing_shadow()?;
|
||||
}
|
||||
}
|
||||
|
||||
/// An object that we use with all the intermediate state needed for the
|
||||
/// cascade.
|
||||
///
|
||||
|
@ -213,44 +250,20 @@ where
|
|||
return;
|
||||
}
|
||||
|
||||
let mut current_containing_shadow = self.rule_hash_target.containing_shadow();
|
||||
while let Some(containing_shadow) = current_containing_shadow {
|
||||
let containing_shadow = containing_shadow_ignoring_svg_use(self.rule_hash_target);
|
||||
let containing_shadow = match containing_shadow {
|
||||
Some(s) => s,
|
||||
None => return,
|
||||
};
|
||||
|
||||
self.matches_document_author_rules = false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
debug_assert!(
|
||||
cascade_data.is_none(),
|
||||
"We allow no stylesheets in <svg:use> subtrees"
|
||||
);
|
||||
|
||||
// NOTE(emilio): Hack so <svg:use> 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 <svg:use>
|
||||
// subtrees are immutable and recreated each time the source
|
||||
// tree changes.
|
||||
//
|
||||
// We historically allow cross-document <svg:use> 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();
|
||||
}
|
||||
}
|
||||
|
||||
/// Collects the rules for the :host pseudo-class.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue