--- a/servo/components/style/applicable_declarations.rs
+++ b/servo/components/style/applicable_declarations.rs
@@ -1,16 +1,16 @@
/* 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/. */
//! Applicable declarations management.
use properties::PropertyDeclarationBlock;
-use rule_tree::{CascadeLevel, StyleSource};
+use rule_tree::{CascadeLevel, ShadowCascadeOrder, StyleSource};
use servo_arc::Arc;
use shared_lock::Locked;
use smallvec::SmallVec;
use std::fmt::{self, Debug};
use std::mem;
/// List of applicable declarations. This is a transient structure that shuttles
/// declarations between selector matching and inserting into the rule tree, and
@@ -78,55 +78,65 @@ impl Debug for SourceOrderAndCascadeLeve
pub struct ApplicableDeclarationBlock {
/// The style source, either a style rule, or a property declaration block.
#[ignore_malloc_size_of = "Arc"]
pub source: StyleSource,
/// The source order of the block, and the cascade level it belongs to.
order_and_level: SourceOrderAndCascadeLevel,
/// The specificity of the selector this block is represented by.
pub specificity: u32,
+ /// The order in the tree of trees we carry on.
+ pub shadow_cascade_order: ShadowCascadeOrder,
}
impl ApplicableDeclarationBlock {
/// Constructs an applicable declaration block from a given property
/// declaration block and importance.
#[inline]
pub fn from_declarations(
declarations: Arc<Locked<PropertyDeclarationBlock>>,
level: CascadeLevel,
) -> Self {
ApplicableDeclarationBlock {
source: StyleSource::Declarations(declarations),
order_and_level: SourceOrderAndCascadeLevel::new(0, level),
specificity: 0,
+ shadow_cascade_order: 0,
}
}
/// Constructs an applicable declaration block from the given components
#[inline]
- pub fn new(source: StyleSource, order: u32, level: CascadeLevel, specificity: u32) -> Self {
+ pub fn new(
+ source: StyleSource,
+ order: u32,
+ level: CascadeLevel,
+ specificity: u32,
+ shadow_cascade_order: u32,
+ ) -> Self {
ApplicableDeclarationBlock {
- source: source,
+ source,
order_and_level: SourceOrderAndCascadeLevel::new(order, level),
- specificity: specificity,
+ specificity,
+ shadow_cascade_order,
}
}
/// Returns the source order of the block.
#[inline]
pub fn source_order(&self) -> u32 {
self.order_and_level.order()
}
/// Returns the cascade level of the block.
#[inline]
pub fn level(&self) -> CascadeLevel {
self.order_and_level.level()
}
- /// Convenience method to consume self and return the source alongside the
- /// level.
+ /// Convenience method to consume self and return the right thing for the
+ /// rule tree to iterate over.
#[inline]
- pub fn order_and_level(self) -> (StyleSource, CascadeLevel) {
+ pub fn for_rule_tree(self) -> (StyleSource, CascadeLevel, ShadowCascadeOrder) {
let level = self.level();
- (self.source, level)
+ (self.source, level, self.shadow_cascade_order)
}
}
--- a/servo/components/style/rule_tree/mod.rs
+++ b/servo/components/style/rule_tree/mod.rs
@@ -157,16 +157,26 @@ impl StyleSource {
///
/// The root node doesn't have a null pointer in the free list, but this value.
const FREE_LIST_SENTINEL: *mut RuleNode = 0x01 as *mut RuleNode;
/// A second sentinel value for the free list, indicating that it's locked (i.e.
/// another thread is currently adding an entry). We spin if we find this value.
const FREE_LIST_LOCKED: *mut RuleNode = 0x02 as *mut RuleNode;
+/// A counter to track how many inner shadow roots rules deep we are.
+///
+/// This is used to handle:
+///
+/// https://drafts.csswg.org/css-scoping/#shadow-cascading
+///
+/// In particular, it'd be `0` for the innermost shadow host, `1` for the next,
+/// and so on.
+pub type ShadowCascadeOrder = u32;
+
impl RuleTree {
/// Construct a new rule tree.
pub fn new() -> Self {
RuleTree {
root: StrongRuleNode::new(Box::new(RuleNode::root())),
}
}
@@ -193,41 +203,61 @@ impl RuleTree {
/// in the rule tree. This allows selector matching to ignore importance,
/// while still maintaining the appropriate cascade order in the rule tree.
pub fn insert_ordered_rules_with_important<'a, I>(
&self,
iter: I,
guards: &StylesheetGuards,
) -> StrongRuleNode
where
- I: Iterator<Item = (StyleSource, CascadeLevel)>,
+ I: Iterator<Item = (StyleSource, CascadeLevel, ShadowCascadeOrder)>,
{
use self::CascadeLevel::*;
let mut current = self.root.clone();
let mut last_level = current.get().level;
let mut found_important = false;
let mut important_style_attr = None;
- let mut important_author = SmallVec::<[StyleSource; 4]>::new();
+
+ let mut important_same_tree = SmallVec::<[StyleSource; 4]>::new();
+ let mut important_inner_shadow = SmallVec::<[SmallVec<[StyleSource; 4]>; 4]>::new();
+ important_inner_shadow.push(SmallVec::new());
+
let mut important_user = SmallVec::<[StyleSource; 4]>::new();
let mut important_ua = SmallVec::<[StyleSource; 4]>::new();
let mut transition = None;
- for (source, level) in iter {
- debug_assert!(last_level <= level, "Not really ordered");
+ let mut last_cascade_order = 0;
+ for (source, level, shadow_cascade_order) in iter {
+ debug_assert!(level >= last_level, "Not really ordered");
debug_assert!(!level.is_important(), "Important levels handled internally");
let any_important = {
let pdb = source.read(level.guard(guards));
pdb.any_important()
};
if any_important {
found_important = true;
match level {
- AuthorNormal => important_author.push(source.clone()),
+ InnerShadowNormal => {
+ debug_assert!(
+ shadow_cascade_order >= last_cascade_order,
+ "Not really ordered"
+ );
+ if shadow_cascade_order > last_cascade_order &&
+ !important_inner_shadow.last().unwrap().is_empty()
+ {
+ last_cascade_order = shadow_cascade_order;
+ important_inner_shadow.push(SmallVec::new());
+ }
+ important_inner_shadow.last_mut().unwrap().push(source.clone())
+ }
+ SameTreeAuthorNormal => {
+ important_same_tree.push(source.clone())
+ },
UANormal => important_ua.push(source.clone()),
UserNormal => important_user.push(source.clone()),
StyleAttributeNormal => {
debug_assert!(important_style_attr.is_none());
important_style_attr = Some(source.clone());
},
_ => {},
};
@@ -260,24 +290,30 @@ impl RuleTree {
return current;
}
//
// Insert important declarations, in order of increasing importance,
// followed by any transition rule.
//
- for source in important_author.drain() {
- current = current.ensure_child(self.root.downgrade(), source, AuthorImportant);
+ for source in important_same_tree.drain() {
+ current = current.ensure_child(self.root.downgrade(), source, SameTreeAuthorImportant);
}
if let Some(source) = important_style_attr {
current = current.ensure_child(self.root.downgrade(), source, StyleAttributeImportant);
}
+ for mut list in important_inner_shadow.drain().rev() {
+ for source in list.drain() {
+ current = current.ensure_child(self.root.downgrade(), source, InnerShadowImportant);
+ }
+ }
+
for source in important_user.drain() {
current = current.ensure_child(self.root.downgrade(), source, UserImportant);
}
for source in important_ua.drain() {
current = current.ensure_child(self.root.downgrade(), source, UAImportant);
}
@@ -290,19 +326,20 @@ impl RuleTree {
/// Given a list of applicable declarations, insert the rules and return the
/// corresponding rule node.
pub fn compute_rule_node(
&self,
applicable_declarations: &mut ApplicableDeclarationList,
guards: &StylesheetGuards,
) -> StrongRuleNode {
- let rules = applicable_declarations.drain().map(|d| d.order_and_level());
- let rule_node = self.insert_ordered_rules_with_important(rules, guards);
- rule_node
+ self.insert_ordered_rules_with_important(
+ applicable_declarations.drain().map(|d| d.for_rule_tree()),
+ guards,
+ )
}
/// Insert the given rules, that must be in proper order by specifity, and
/// return the corresponding rule node representing the last inserted one.
pub fn insert_ordered_rules<'a, I>(&self, iter: I) -> StrongRuleNode
where
I: Iterator<Item = (StyleSource, CascadeLevel)>,
{
@@ -376,18 +413,18 @@ impl RuleTree {
// same as `pdb`, we're done, and `path` is still valid.
//
// TODO(emilio): Another potential optimization is the one where
// we can just replace the rule at that level for `pdb`, and
// then we don't need to re-create the children, and `path` is
// also equally valid. This is less likely, and would require an
// in-place mutation of the source, which is, at best, fiddly,
// so let's skip it for now.
- let is_here_already = match ¤t.get().source {
- &StyleSource::Declarations(ref already_here) => {
+ let is_here_already = match current.get().source {
+ StyleSource::Declarations(ref already_here) => {
pdb.with_arc(|arc| Arc::ptr_eq(arc, already_here))
},
_ => unreachable!("Replacing non-declarations style?"),
};
if is_here_already {
debug!("Picking the fast path in rule replacement");
return None;
@@ -495,41 +532,63 @@ const RULE_TREE_GC_INTERVAL: usize = 300
///
/// Presentational hints for SVG and HTML are in the "author-level
/// zero-specificity" level, that is, right after user rules, and before author
/// rules.
///
/// The order of variants declared here is significant, and must be in
/// _ascending_ order of precedence.
///
+/// See also [4] for the Shadow DOM bits. We rely on the invariant that rules
+/// from outside the tree the element is in can't affect the element.
+///
+/// The opposite is not true (i.e., :host and ::slotted) from an "inner" shadow
+/// tree may affect an element connected to the document or an "outer" shadow
+/// tree.
+///
+/// We need to differentiate between rules from the same tree and "inner" shadow
+/// trees in order to be able to find the right position for the style attribute
+/// easily. Otherwise we wouldn't be able to avoid selector-matching when a
+/// style attribute is added or removed.
+///
/// [1]: https://drafts.csswg.org/css-cascade/#cascade-origin
/// [2]: https://drafts.csswg.org/css-cascade/#preshint
/// [3]: https://html.spec.whatwg.org/multipage/#presentational-hints
+/// [4]: https://drafts.csswg.org/css-scoping/#shadow-cascading
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
pub enum CascadeLevel {
/// Normal User-Agent rules.
UANormal = 0,
/// User normal rules.
UserNormal,
/// Presentational hints.
PresHints,
- /// Author normal rules.
- AuthorNormal,
+ /// Shadow DOM styles from "inner" shadow trees.
+ ///
+ /// See above for why this is needed instead of merging InnerShadowNormal,
+ /// SameTreeAuthorNormal and StyleAttributeNormal inside something like
+ /// AuthorNormal.
+ InnerShadowNormal,
+ /// Author normal rules from the same tree the element is in.
+ SameTreeAuthorNormal,
/// Style attribute normal rules.
StyleAttributeNormal,
/// SVG SMIL animations.
SMILOverride,
/// CSS animations and script-generated animations.
Animations,
- /// Author-supplied important rules.
- AuthorImportant,
+ /// Author-supplied important rules from the same tree the element came
+ /// from.
+ SameTreeAuthorImportant,
/// Style attribute important rules.
StyleAttributeImportant,
+ /// Shadow DOM important rules.
+ InnerShadowImportant,
/// User important rules.
UserImportant,
/// User-agent important rules.
UAImportant,
/// Transitions
///
/// NB: If this changes from being last, change from_byte below.
Transitions,
@@ -566,17 +625,18 @@ impl CascadeLevel {
}
}
/// Returns whether this cascade level represents important rules of some
/// sort.
#[inline]
pub fn is_important(&self) -> bool {
match *self {
- CascadeLevel::AuthorImportant |
+ CascadeLevel::SameTreeAuthorImportant |
+ CascadeLevel::InnerShadowImportant |
CascadeLevel::StyleAttributeImportant |
CascadeLevel::UserImportant |
CascadeLevel::UAImportant => true,
_ => false,
}
}
/// Returns the importance relevant for this rule. Pretty similar to
@@ -1297,21 +1357,23 @@ impl StrongRuleNode {
have_explicit_ua_inherit = true;
inherited_properties.insert(id);
}
}
}
},
// Author rules:
CascadeLevel::PresHints |
- CascadeLevel::AuthorNormal |
+ CascadeLevel::SameTreeAuthorNormal |
+ CascadeLevel::InnerShadowNormal |
CascadeLevel::StyleAttributeNormal |
CascadeLevel::SMILOverride |
CascadeLevel::Animations |
- CascadeLevel::AuthorImportant |
+ CascadeLevel::SameTreeAuthorImportant |
+ CascadeLevel::InnerShadowImportant |
CascadeLevel::StyleAttributeImportant |
CascadeLevel::Transitions => {
for (id, declaration) in longhands {
if properties.contains(id) {
if !author_colors_allowed {
if let PropertyDeclaration::BackgroundColor(ref color) =
*declaration
{
--- a/servo/components/style/selector_map.rs
+++ b/servo/components/style/selector_map.rs
@@ -9,17 +9,17 @@ use {Atom, LocalName, WeakAtom};
use applicable_declarations::ApplicableDeclarationList;
use context::QuirksMode;
use dom::TElement;
use fallible::FallibleVec;
use hash::{HashMap, HashSet};
use hash::map as hash_map;
use hashglobe::FailedAllocationError;
use precomputed_hash::PrecomputedHash;
-use rule_tree::CascadeLevel;
+use rule_tree::{CascadeLevel, ShadowCascadeOrder};
use selector_parser::SelectorImpl;
use selectors::matching::{matches_selector, ElementSelectorFlags, MatchingContext};
use selectors::parser::{Combinator, Component, SelectorIter};
use smallvec::SmallVec;
use std::hash::{BuildHasherDefault, Hash, Hasher};
use stylist::Rule;
/// A hasher implementation that doesn't hash anything, because it expects its
@@ -158,16 +158,17 @@ impl SelectorMap<Rule> {
pub fn get_all_matching_rules<E, F>(
&self,
element: E,
rule_hash_target: E,
matching_rules_list: &mut ApplicableDeclarationList,
context: &mut MatchingContext<E::Impl>,
flags_setter: &mut F,
cascade_level: CascadeLevel,
+ shadow_cascade_order: ShadowCascadeOrder,
) where
E: TElement,
F: FnMut(&E, ElementSelectorFlags),
{
if self.is_empty() {
return;
}
@@ -180,80 +181,85 @@ impl SelectorMap<Rule> {
if let Some(rules) = self.id_hash.get(id, quirks_mode) {
SelectorMap::get_matching_rules(
element,
rules,
matching_rules_list,
context,
flags_setter,
cascade_level,
+ shadow_cascade_order,
)
}
}
rule_hash_target.each_class(|class| {
if let Some(rules) = self.class_hash.get(&class, quirks_mode) {
SelectorMap::get_matching_rules(
element,
rules,
matching_rules_list,
context,
flags_setter,
cascade_level,
+ shadow_cascade_order,
)
}
});
if let Some(rules) = self.local_name_hash.get(rule_hash_target.local_name()) {
SelectorMap::get_matching_rules(
element,
rules,
matching_rules_list,
context,
flags_setter,
cascade_level,
+ shadow_cascade_order,
)
}
SelectorMap::get_matching_rules(
element,
&self.other,
matching_rules_list,
context,
flags_setter,
cascade_level,
+ shadow_cascade_order,
);
// Sort only the rules we just added.
matching_rules_list[init_len..]
.sort_unstable_by_key(|block| (block.specificity, block.source_order()));
}
/// Adds rules in `rules` that match `element` to the `matching_rules` list.
fn get_matching_rules<E, F>(
element: E,
rules: &[Rule],
matching_rules: &mut ApplicableDeclarationList,
context: &mut MatchingContext<E::Impl>,
flags_setter: &mut F,
cascade_level: CascadeLevel,
+ shadow_cascade_order: ShadowCascadeOrder,
) where
E: TElement,
F: FnMut(&E, ElementSelectorFlags),
{
for rule in rules {
if matches_selector(
&rule.selector,
0,
Some(&rule.hashes),
&element,
context,
flags_setter,
) {
- matching_rules.push(rule.to_applicable_declaration_block(cascade_level));
+ matching_rules.push(rule.to_applicable_declaration_block(cascade_level, shadow_cascade_order));
}
}
}
}
impl<T: SelectorMapEntry> SelectorMap<T> {
/// Inserts into the correct hash, trying id, class, and localname.
pub fn insert(
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -18,17 +18,17 @@ use invalidation::media_queries::{Effect
#[cfg(feature = "gecko")]
use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps};
#[cfg(feature = "gecko")]
use malloc_size_of::MallocUnconditionalShallowSizeOf;
use media_queries::Device;
use properties::{self, CascadeFlags, ComputedValues};
use properties::{AnimationRules, PropertyDeclarationBlock};
use rule_cache::{RuleCache, RuleCacheConditions};
-use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
+use rule_tree::{CascadeLevel, RuleTree, ShadowCascadeOrder, StrongRuleNode, StyleSource};
use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry};
use selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap};
use selectors::NthIndexCache;
use selectors::attr::{CaseSensitivity, NamespaceConstraint};
use selectors::bloom::{BloomFilter, NonCountingBloomFilter};
use selectors::matching::{matches_selector, ElementSelectorFlags, MatchingContext, MatchingMode};
use selectors::matching::VisitedHandlingMode;
use selectors::parser::{AncestorHashes, Combinator, Component, Selector};
@@ -688,17 +688,17 @@ impl Stylist {
},
None => Some(declarations),
},
None => extra_declarations.as_ref(),
};
match declarations {
Some(decls) => self.rule_tree.insert_ordered_rules_with_important(
- decls.into_iter().map(|a| (a.source.clone(), a.level())),
+ decls.into_iter().map(|a| a.clone().for_rule_tree()),
guards,
),
None => self.rule_tree.root().clone(),
}
}
/// Returns the style for an anonymous box of the given type.
///
@@ -1015,17 +1015,17 @@ impl Stylist {
AnimationRules(None, None),
rule_inclusion,
&mut declarations,
&mut matching_context,
&mut set_selector_flags,
);
if !declarations.is_empty() {
let rule_node = self.rule_tree.insert_ordered_rules_with_important(
- declarations.drain().map(|a| a.order_and_level()),
+ declarations.drain().map(|a| a.for_rule_tree()),
guards,
);
if rule_node != *self.rule_tree.root() {
visited_rules = Some(rule_node);
}
}
}
@@ -1182,16 +1182,17 @@ impl Stylist {
{
map.get_all_matching_rules(
element,
rule_hash_target,
applicable_declarations,
context,
flags_setter,
CascadeLevel::UANormal,
+ 0,
);
}
// NB: the following condition, although it may look somewhat
// inaccurate, would be equivalent to something like:
//
// element.matches_user_and_author_rules() ||
// (is_implemented_pseudo &&
@@ -1203,16 +1204,17 @@ impl Stylist {
if let Some(map) = self.cascade_data.user.normal_rules(pseudo_element) {
map.get_all_matching_rules(
element,
rule_hash_target,
applicable_declarations,
context,
flags_setter,
CascadeLevel::UserNormal,
+ 0,
);
}
}
if pseudo_element.is_none() && !only_default_rules {
// Presentational hints.
//
// These go before author rules, but after user rules, see:
@@ -1227,16 +1229,17 @@ impl Stylist {
for declaration in &applicable_declarations[length_before_preshints..] {
assert_eq!(declaration.level(), CascadeLevel::PresHints);
}
}
}
}
let mut match_document_author_rules = matches_author_rules;
+ let mut shadow_cascade_order = 0;
// XBL / Shadow DOM rules, which are author rules too.
//
// TODO(emilio): Cascade order here is wrong for Shadow DOM. In
// particular, normally document rules override ::slotted() rules, but
// for !important it should be the other way around. So probably we need
// to add some sort of AuthorScoped cascade level or something.
if matches_author_rules && !only_default_rules {
@@ -1244,19 +1247,21 @@ impl Stylist {
if let Some(map) = shadow.style_data().host_rules(pseudo_element) {
context.with_shadow_host(Some(rule_hash_target), |context| {
map.get_all_matching_rules(
element,
rule_hash_target,
applicable_declarations,
context,
flags_setter,
- CascadeLevel::AuthorNormal,
+ CascadeLevel::InnerShadowNormal,
+ shadow_cascade_order,
);
});
+ shadow_cascade_order += 1;
}
}
// Match slotted rules in reverse order, so that the outer slotted
// rules come before the inner rules (and thus have less priority).
let mut slots = SmallVec::<[_; 3]>::new();
let mut current = rule_hash_target.assigned_slot();
while let Some(slot) = current {
@@ -1270,86 +1275,90 @@ impl Stylist {
if let Some(map) = styles.slotted_rules(pseudo_element) {
context.with_shadow_host(Some(shadow.host()), |context| {
map.get_all_matching_rules(
element,
rule_hash_target,
applicable_declarations,
context,
flags_setter,
- CascadeLevel::AuthorNormal,
+ CascadeLevel::InnerShadowNormal,
+ shadow_cascade_order,
);
});
+ shadow_cascade_order += 1;
}
}
if let Some(containing_shadow) = rule_hash_target.containing_shadow() {
let cascade_data = containing_shadow.style_data();
if let Some(map) = cascade_data.normal_rules(pseudo_element) {
context.with_shadow_host(Some(containing_shadow.host()), |context| {
map.get_all_matching_rules(
element,
rule_hash_target,
applicable_declarations,
context,
flags_setter,
- CascadeLevel::AuthorNormal,
+ CascadeLevel::SameTreeAuthorNormal,
+ shadow_cascade_order,
);
});
+ shadow_cascade_order += 1;
}
match_document_author_rules = false;
}
}
// FIXME(emilio): It looks very wrong to match XBL rules even for
// getDefaultComputedStyle!
//
// Also, this doesn't account for the author_styles_enabled stuff.
let cut_xbl_binding_inheritance =
element.each_xbl_cascade_data(|cascade_data, quirks_mode| {
if let Some(map) = cascade_data.normal_rules(pseudo_element) {
// NOTE(emilio): This is needed because the XBL stylist may
// think it has a different quirks mode than the document.
- //
- // FIXME(emilio): this should use the same VisitedMatchingMode
- // as `context`, write a test-case of :visited not working on
- // Shadow DOM and fix it!
let mut matching_context = MatchingContext::new(
context.matching_mode(),
context.bloom_filter,
context.nth_index_cache.as_mut().map(|s| &mut **s),
quirks_mode,
);
matching_context.pseudo_element_matching_fn =
context.pseudo_element_matching_fn;
+ // SameTreeAuthorNormal instead of InnerShadowNormal to
+ // preserve behavior, though that's kinda fishy...
map.get_all_matching_rules(
element,
rule_hash_target,
applicable_declarations,
&mut matching_context,
flags_setter,
- CascadeLevel::AuthorNormal,
+ CascadeLevel::SameTreeAuthorNormal,
+ shadow_cascade_order,
);
}
});
match_document_author_rules &= !cut_xbl_binding_inheritance;
if match_document_author_rules && !only_default_rules {
// Author normal rules.
if let Some(map) = self.cascade_data.author.normal_rules(pseudo_element) {
map.get_all_matching_rules(
element,
rule_hash_target,
applicable_declarations,
context,
flags_setter,
- CascadeLevel::AuthorNormal,
+ CascadeLevel::SameTreeAuthorNormal,
+ shadow_cascade_order,
);
}
}
if !only_default_rules {
// Style attribute ("Normal override declarations").
if let Some(sa) = style_attribute {
applicable_declarations.push(ApplicableDeclarationBlock::from_declarations(
@@ -2167,16 +2176,17 @@ impl CascadeData {
.as_mut()
.expect("Expected precomputed declarations for the UA level")
.get_or_insert_with(&pseudo.canonical(), Vec::new)
.push(ApplicableDeclarationBlock::new(
StyleSource::Style(locked.clone()),
self.rules_source_order,
CascadeLevel::UANormal,
selector.specificity(),
+ 0,
));
continue;
}
}
let hashes = AncestorHashes::new(&selector, quirks_mode);
let rule = Rule::new(
@@ -2463,19 +2473,20 @@ impl Rule {
self.selector.specificity()
}
/// Turns this rule into an `ApplicableDeclarationBlock` for the given
/// cascade level.
pub fn to_applicable_declaration_block(
&self,
level: CascadeLevel,
+ shadow_cascade_order: ShadowCascadeOrder,
) -> ApplicableDeclarationBlock {
let source = StyleSource::Style(self.style_rule.clone());
- ApplicableDeclarationBlock::new(source, self.source_order, level, self.specificity())
+ ApplicableDeclarationBlock::new(source, self.source_order, level, self.specificity(), shadow_cascade_order)
}
/// Creates a new Rule.
pub fn new(
selector: Selector<SelectorImpl>,
hashes: AncestorHashes,
style_rule: Arc<Locked<StyleRule>>,
source_order: u32,
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -2704,17 +2704,17 @@ pub unsafe extern "C" fn Servo_ComputedV
let page_decls = match pseudo {
PseudoElement::PageContent => {
let mut declarations = vec![];
let iter = data.stylist.iter_extra_data_origins_rev();
for (data, origin) in iter {
let level = match origin {
Origin::UserAgent => CascadeLevel::UANormal,
Origin::User => CascadeLevel::UserNormal,
- Origin::Author => CascadeLevel::AuthorNormal,
+ Origin::Author => CascadeLevel::SameTreeAuthorNormal,
};
for rule in data.pages.iter() {
declarations.push(ApplicableDeclarationBlock::from_declarations(
rule.read_with(level.guard(&guards)).block.clone(),
level
));
}
}
--- a/servo/ports/geckolib/tests/size_of.rs
+++ b/servo/ports/geckolib/tests/size_of.rs
@@ -30,17 +30,17 @@ size_of_test!(test_size_of_cv, ComputedV
size_of_test!(test_size_of_option_arc_cv, Option<Arc<ComputedValues>>, 8);
size_of_test!(test_size_of_option_rule_node, Option<StrongRuleNode>, 8);
size_of_test!(test_size_of_element_styles, ElementStyles, 16);
size_of_test!(test_size_of_element_data, ElementData, 24);
size_of_test!(test_size_of_property_declaration, style::properties::PropertyDeclaration, 32);
-size_of_test!(test_size_of_application_declaration_block, ApplicableDeclarationBlock, 24);
+size_of_test!(test_size_of_application_declaration_block, ApplicableDeclarationBlock, 28);
size_of_test!(test_size_of_rule_node, RuleNode, 80);
// This is huge, but we allocate it on the stack and then never move it,
// we only pass `&mut SourcePropertyDeclaration` references around.
size_of_test!(test_size_of_parsed_declaration, style::properties::SourcePropertyDeclaration, 608);
size_of_test!(test_size_of_computed_image, computed::image::Image, 32);
size_of_test!(test_size_of_specified_image, specified::image::Image, 32);
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-scoping/shadow-cascade-order-001.html.ini
+++ /dev/null
@@ -1,43 +0,0 @@
-[shadow-cascade-order-001.html]
- [D1. document vs ::slotted both with !important, ::slotted rule should win for open mode.]
- expected: FAIL
-
- [D2. document vs :host both with !important, :host rule should win for open mode.]
- expected: FAIL
-
- [D4. ::slotted vs :host both with !important, later in tree-of-trees rule should win for open mode.]
- expected: FAIL
-
- [D5. ::slotted vs inline both with !important, ::slotted rule should win for open mode.]
- expected: FAIL
-
- [D6. :host vs inline both with !important, :host rule should win for open mode.]
- expected: FAIL
-
- [E2. all styles with !important applied, rule in the last tree-of-trees should win for open mode.]
- expected: FAIL
-
- [F6. all rules with !important, the last rule in tree-of-trees should win for open mode.]
- expected: FAIL
-
- [D1. document vs ::slotted both with !important, ::slotted rule should win for closed mode.]
- expected: FAIL
-
- [D2. document vs :host both with !important, :host rule should win for closed mode.]
- expected: FAIL
-
- [D4. ::slotted vs :host both with !important, later in tree-of-trees rule should win for closed mode.]
- expected: FAIL
-
- [D5. ::slotted vs inline both with !important, ::slotted rule should win for closed mode.]
- expected: FAIL
-
- [D6. :host vs inline both with !important, :host rule should win for closed mode.]
- expected: FAIL
-
- [E2. all styles with !important applied, rule in the last tree-of-trees should win for closed mode.]
- expected: FAIL
-
- [F6. all rules with !important, the last rule in tree-of-trees should win for closed mode.]
- expected: FAIL
-