Bug 1588431 - Fix cascade order of shadow parts. r=heycam
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 14 Nov 2019 02:49:54 +0000
changeset 501906 15ba6d5159446877cac2dee1ffa17cf53aba8d7a
parent 501905 9f62b84d6bbb31cb27a8458946fa9fe4d86c8275
child 501907 06945900e072481a3ecacf3f75a1ea66fc422176
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1588431
milestone72.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 1588431 - Fix cascade order of shadow parts. r=heycam This moves the shadow cascade order into the cascade level, and refactors the code a bit for that. Differential Revision: https://phabricator.services.mozilla.com/D49988
servo/components/style/applicable_declarations.rs
servo/components/style/gecko/pseudo_element.rs
servo/components/style/matching.rs
servo/components/style/properties/cascade.rs
servo/components/style/rule_collector.rs
servo/components/style/rule_tree/mod.rs
servo/components/style/selector_map.rs
servo/components/style/servo/selector_parser.rs
servo/components/style/stylist.rs
servo/ports/geckolib/glue.rs
testing/web-platform/meta/css/css-shadow-parts/simple-important-important.html.ini
testing/web-platform/meta/css/css-shadow-parts/simple-inline.html.ini
--- a/servo/components/style/applicable_declarations.rs
+++ b/servo/components/style/applicable_declarations.rs
@@ -1,99 +1,50 @@
 /* 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 https://mozilla.org/MPL/2.0/. */
 
 //! Applicable declarations management.
 
 use crate::properties::PropertyDeclarationBlock;
-use crate::rule_tree::{CascadeLevel, ShadowCascadeOrder, StyleSource};
+use crate::rule_tree::{CascadeLevel, StyleSource};
 use crate::shared_lock::Locked;
 use servo_arc::Arc;
 use smallvec::SmallVec;
-use std::fmt::{self, Debug};
 
 /// List of applicable declarations. This is a transient structure that shuttles
 /// declarations between selector matching and inserting into the rule tree, and
 /// therefore we want to avoid heap-allocation where possible.
 ///
 /// In measurements on wikipedia, we pretty much never have more than 8 applicable
 /// declarations, so we could consider making this 8 entries instead of 16.
 /// However, it may depend a lot on workload, and stack space is cheap.
 pub type ApplicableDeclarationList = SmallVec<[ApplicableDeclarationBlock; 16]>;
 
-/// Blink uses 18 bits to store source order, and does not check overflow [1].
-/// That's a limit that could be reached in realistic webpages, so we use
-/// 24 bits and enforce defined behavior in the overflow case.
-///
-/// [1] https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/css/
-///     RuleSet.h?l=128&rcl=90140ab80b84d0f889abc253410f44ed54ae04f3
-const SOURCE_ORDER_SHIFT: usize = 0;
-const SOURCE_ORDER_BITS: usize = 24;
-const SOURCE_ORDER_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1;
-const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX << SOURCE_ORDER_SHIFT;
-
-/// We store up-to-15 shadow order levels.
-///
-/// You'd need an element slotted across 16 components with ::slotted rules to
-/// trigger this as of this writing, which looks... Unlikely.
-const SHADOW_CASCADE_ORDER_SHIFT: usize = SOURCE_ORDER_BITS;
-const SHADOW_CASCADE_ORDER_BITS: usize = 4;
-const SHADOW_CASCADE_ORDER_MAX: u8 = (1 << SHADOW_CASCADE_ORDER_BITS) - 1;
-const SHADOW_CASCADE_ORDER_MASK: u32 =
-    (SHADOW_CASCADE_ORDER_MAX as u32) << SHADOW_CASCADE_ORDER_SHIFT;
-
-const CASCADE_LEVEL_SHIFT: usize = SOURCE_ORDER_BITS + SHADOW_CASCADE_ORDER_BITS;
-const CASCADE_LEVEL_BITS: usize = 4;
-const CASCADE_LEVEL_MAX: u8 = (1 << CASCADE_LEVEL_BITS) - 1;
-const CASCADE_LEVEL_MASK: u32 = (CASCADE_LEVEL_MAX as u32) << CASCADE_LEVEL_SHIFT;
-
 /// Stores the source order of a block, the cascade level it belongs to, and the
 /// counter needed to handle Shadow DOM cascade order properly.
-#[derive(Clone, Copy, Eq, MallocSizeOf, PartialEq)]
-struct ApplicableDeclarationBits(u32);
+///
+/// FIXME(emilio): Optimize storage.
+#[derive(Clone, Copy, Eq, MallocSizeOf, PartialEq, Debug)]
+struct ApplicableDeclarationBits {
+    source_order: u32,
+    cascade_level: CascadeLevel,
+}
 
 impl ApplicableDeclarationBits {
-    fn new(
-        source_order: u32,
-        cascade_level: CascadeLevel,
-        shadow_cascade_order: ShadowCascadeOrder,
-    ) -> Self {
-        debug_assert!(
-            cascade_level as u8 <= CASCADE_LEVEL_MAX,
-            "Gotta find more bits!"
-        );
-        let mut bits = ::std::cmp::min(source_order, SOURCE_ORDER_MAX);
-        bits |= ((shadow_cascade_order & SHADOW_CASCADE_ORDER_MAX) as u32) <<
-            SHADOW_CASCADE_ORDER_SHIFT;
-        bits |= (cascade_level as u8 as u32) << CASCADE_LEVEL_SHIFT;
-        ApplicableDeclarationBits(bits)
+    fn new(source_order: u32, cascade_level: CascadeLevel) -> Self {
+        Self { source_order, cascade_level }
     }
 
     fn source_order(&self) -> u32 {
-        (self.0 & SOURCE_ORDER_MASK) >> SOURCE_ORDER_SHIFT
-    }
-
-    fn shadow_cascade_order(&self) -> ShadowCascadeOrder {
-        ((self.0 & SHADOW_CASCADE_ORDER_MASK) >> SHADOW_CASCADE_ORDER_SHIFT) as ShadowCascadeOrder
+        self.source_order
     }
 
     fn level(&self) -> CascadeLevel {
-        let byte = ((self.0 & CASCADE_LEVEL_MASK) >> CASCADE_LEVEL_SHIFT) as u8;
-        unsafe { CascadeLevel::from_byte(byte) }
-    }
-}
-
-impl Debug for ApplicableDeclarationBits {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.debug_struct("ApplicableDeclarationBits")
-            .field("source_order", &self.source_order())
-            .field("shadow_cascade_order", &self.shadow_cascade_order())
-            .field("level", &self.level())
-            .finish()
+        self.cascade_level
     }
 }
 
 /// A property declaration together with its precedence among rules of equal
 /// specificity so that we can sort them.
 ///
 /// This represents the declarations in a given declaration block for a given
 /// importance.
@@ -114,33 +65,32 @@ impl ApplicableDeclarationBlock {
     /// declaration block and importance.
     #[inline]
     pub fn from_declarations(
         declarations: Arc<Locked<PropertyDeclarationBlock>>,
         level: CascadeLevel,
     ) -> Self {
         ApplicableDeclarationBlock {
             source: StyleSource::from_declarations(declarations),
-            bits: ApplicableDeclarationBits::new(0, level, 0),
+            bits: ApplicableDeclarationBits::new(0, level),
             specificity: 0,
         }
     }
 
     /// Constructs an applicable declaration block from the given components
     #[inline]
     pub fn new(
         source: StyleSource,
         order: u32,
         level: CascadeLevel,
         specificity: u32,
-        shadow_cascade_order: ShadowCascadeOrder,
     ) -> Self {
         ApplicableDeclarationBlock {
             source,
-            bits: ApplicableDeclarationBits::new(order, level, shadow_cascade_order),
+            bits: ApplicableDeclarationBits::new(order, level),
             specificity,
         }
     }
 
     /// Returns the source order of the block.
     #[inline]
     pub fn source_order(&self) -> u32 {
         self.bits.source_order()
@@ -150,14 +100,13 @@ impl ApplicableDeclarationBlock {
     #[inline]
     pub fn level(&self) -> CascadeLevel {
         self.bits.level()
     }
 
     /// Convenience method to consume self and return the right thing for the
     /// rule tree to iterate over.
     #[inline]
-    pub fn for_rule_tree(self) -> (StyleSource, CascadeLevel, ShadowCascadeOrder) {
+    pub fn for_rule_tree(self) -> (StyleSource, CascadeLevel) {
         let level = self.level();
-        let cascade_order = self.bits.shadow_cascade_order();
-        (self.source, level, cascade_order)
+        (self.source, level)
     }
 }
--- a/servo/components/style/gecko/pseudo_element.rs
+++ b/servo/components/style/gecko/pseudo_element.rs
@@ -135,16 +135,22 @@ impl PseudoElement {
     }
 
     /// Whether this pseudo-element is ::-moz-fieldset-content.
     #[inline]
     pub fn is_fieldset_content(&self) -> bool {
         *self == PseudoElement::FieldsetContent
     }
 
+    /// Whether this pseudo-element is the ::-moz-color-swatch pseudo.
+    #[inline]
+    pub fn is_color_swatch(&self) -> bool {
+        *self == PseudoElement::MozColorSwatch
+    }
+
     /// Whether this pseudo-element is lazily-cascaded.
     #[inline]
     pub fn is_lazy(&self) -> bool {
         !self.is_eager() && !self.is_precomputed()
     }
 
     /// Whether this pseudo-element supports user action selectors.
     pub fn supports_user_action_state(&self) -> bool {
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -132,22 +132,22 @@ trait PrivateMatchMethods: TElement {
             important_rules_changed
         };
 
         if !context.shared.traversal_flags.for_animation_only() {
             let mut result = false;
             if replacements.contains(RestyleHint::RESTYLE_STYLE_ATTRIBUTE) {
                 let style_attribute = self.style_attribute();
                 result |= replace_rule_node(
-                    CascadeLevel::StyleAttributeNormal,
+                    CascadeLevel::same_tree_author_normal(),
                     style_attribute,
                     primary_rules,
                 );
                 result |= replace_rule_node(
-                    CascadeLevel::StyleAttributeImportant,
+                    CascadeLevel::same_tree_author_important(),
                     style_attribute,
                     primary_rules,
                 );
                 // FIXME(emilio): Still a hack!
                 self.unset_dirty_style_attribute();
             }
             return result;
         }
--- a/servo/components/style/properties/cascade.rs
+++ b/servo/components/style/properties/cascade.rs
@@ -341,26 +341,20 @@ fn should_ignore_declaration_when_ignori
     }
 
     let is_ua_or_user_rule =
         matches!(cascade_level.origin(), Origin::User | Origin::UserAgent);
     if is_ua_or_user_rule {
         return false;
     }
 
-    let is_style_attribute = matches!(
-        cascade_level,
-        CascadeLevel::StyleAttributeNormal | CascadeLevel::StyleAttributeImportant
-    );
-
-    // Don't override colors on pseudo-element's style attributes. The
-    // background-color on ::-moz-color-swatch is an example. Those are set
-    // as an author style (via the style attribute), but it's pretty
-    // important for it to show up for obvious reasons :)
-    if pseudo.is_some() && is_style_attribute {
+    // Don't override background-color on ::-moz-color-swatch. It is set as an
+    // author style (via the style attribute), but it's pretty important for it
+    // to show up for obvious reasons :)
+    if pseudo.map_or(false, |p| p.is_color_swatch()) && longhand_id == LonghandId::BackgroundColor {
         return false;
     }
 
     // Treat background-color a bit differently.  If the specified color is
     // anything other than a fully transparent color, convert it into the
     // Device's default background color.
     // Also: for now, we treat background-image a bit differently, too.
     // background-image is marked as ignored, but really, we only ignore
--- a/servo/components/style/rule_collector.rs
+++ b/servo/components/style/rule_collector.rs
@@ -74,17 +74,16 @@ where
     pseudo_element: Option<&'a PseudoElement>,
     style_attribute: Option<ArcBorrow<'a, Locked<PropertyDeclarationBlock>>>,
     smil_override: Option<ArcBorrow<'a, Locked<PropertyDeclarationBlock>>>,
     animation_rules: AnimationRules,
     rule_inclusion: RuleInclusion,
     rules: &'a mut ApplicableDeclarationList,
     context: &'a mut MatchingContext<'b, E::Impl>,
     flags_setter: &'a mut F,
-    shadow_cascade_order: ShadowCascadeOrder,
     matches_user_and_author_rules: bool,
     matches_document_author_rules: bool,
 }
 
 impl<'a, 'b: 'a, E, F: 'a> RuleCollector<'a, 'b, E, F>
 where
     E: TElement,
     F: FnMut(&E, ElementSelectorFlags),
@@ -127,27 +126,26 @@ where
             pseudo_element,
             style_attribute,
             smil_override,
             animation_rules,
             rule_inclusion,
             context,
             flags_setter,
             rules,
-            shadow_cascade_order: 0,
             matches_user_and_author_rules,
             matches_document_author_rules: matches_user_and_author_rules,
         }
     }
 
     fn collect_stylist_rules(&mut self, origin: Origin) {
         let cascade_level = match origin {
             Origin::UserAgent => CascadeLevel::UANormal,
             Origin::User => CascadeLevel::UserNormal,
-            Origin::Author => CascadeLevel::SameTreeAuthorNormal,
+            Origin::Author => CascadeLevel::same_tree_author_normal(),
         };
 
         let cascade_data = self.stylist.cascade_data().borrow_for_origin(origin);
         let map = match cascade_data.normal_rules(self.pseudo_element) {
             Some(m) => m,
             None => return,
         };
 
@@ -193,75 +191,81 @@ where
     fn collect_rules_in_shadow_tree(
         &mut self,
         shadow_host: E,
         map: &SelectorMap<Rule>,
         cascade_level: CascadeLevel,
     ) {
         debug_assert!(shadow_host.shadow_root().is_some());
         self.collect_rules_internal(Some(shadow_host), map, cascade_level);
-        self.shadow_cascade_order += 1;
     }
 
     #[inline]
     fn collect_rules_internal(
         &mut self,
         shadow_host: Option<E>,
         map: &SelectorMap<Rule>,
         cascade_level: CascadeLevel,
     ) {
         let element = self.element;
         let rule_hash_target = self.rule_hash_target;
         let rules = &mut self.rules;
         let flags_setter = &mut self.flags_setter;
-        let shadow_cascade_order = self.shadow_cascade_order;
         let start = rules.len();
         self.context.with_shadow_host(shadow_host, |context| {
             map.get_all_matching_rules(
                 element,
                 rule_hash_target,
                 rules,
                 context,
                 flags_setter,
                 cascade_level,
-                shadow_cascade_order,
             );
         });
         sort_rules_from(rules, start);
     }
 
-    /// Collects the rules for the ::slotted pseudo-element.
-    fn collect_slotted_rules(&mut self) {
+    /// Collects the rules for the ::slotted pseudo-element and the :host
+    /// pseudo-class.
+    fn collect_host_and_slotted_rules(&mut self) {
         let mut slots = SmallVec::<[_; 3]>::new();
         let mut current = self.rule_hash_target.assigned_slot();
+        let mut shadow_cascade_order = ShadowCascadeOrder::for_outermost_shadow_tree();
+
         while let Some(slot) = current {
             debug_assert!(
                 self.matches_user_and_author_rules,
                 "We should not slot NAC anywhere"
             );
             slots.push(slot);
             current = slot.assigned_slot();
+            shadow_cascade_order.dec();
         }
 
+        self.collect_host_rules(shadow_cascade_order);
+
         // Match slotted rules in reverse order, so that the outer slotted rules
         // come before the inner rules (and thus have less priority).
         for slot in slots.iter().rev() {
+            shadow_cascade_order.inc();
+
             let shadow = slot.containing_shadow().unwrap();
             let data = match shadow.style_data() {
                 Some(d) => d,
                 None => continue,
             };
             let slotted_rules = match data.slotted_rules(self.pseudo_element) {
                 Some(r) => r,
                 None => continue,
             };
+
             self.collect_rules_in_shadow_tree(
                 shadow.host(),
                 slotted_rules,
-                CascadeLevel::InnerShadowNormal,
+                CascadeLevel::AuthorNormal { shadow_cascade_order },
             );
         }
     }
 
     fn collect_normal_rules_from_containing_shadow_tree(&mut self) {
         if !self.matches_user_and_author_rules {
             return;
         }
@@ -272,22 +276,22 @@ where
             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);
+            self.collect_rules_in_shadow_tree(host, map, CascadeLevel::same_tree_author_normal());
         }
     }
 
     /// Collects the rules for the :host pseudo-class.
-    fn collect_host_rules(&mut self) {
+    fn collect_host_rules(&mut self, shadow_cascade_order: ShadowCascadeOrder) {
         let shadow = match self.rule_hash_target.shadow_root() {
             Some(s) => s,
             None => return,
         };
 
         debug_assert!(
             self.matches_user_and_author_rules,
             "NAC should not be a shadow host"
@@ -302,17 +306,17 @@ where
             Some(rules) => rules,
             None => return,
         };
 
         let rule_hash_target = self.rule_hash_target;
         self.collect_rules_in_shadow_tree(
             rule_hash_target,
             host_rules,
-            CascadeLevel::InnerShadowNormal,
+            CascadeLevel::AuthorNormal { shadow_cascade_order },
         );
     }
 
     fn collect_document_author_rules(&mut self) {
         if !self.matches_document_author_rules {
             return;
         }
 
@@ -337,57 +341,53 @@ where
                 .and_then(|data| data.part_rules(self.pseudo_element)),
             None => self
                 .stylist
                 .cascade_data()
                 .borrow_for_origin(Origin::Author)
                 .part_rules(self.pseudo_element),
         };
 
-        // TODO(emilio): SameTreeAuthorNormal is a bit of a lie here, we may
-        // need an OuterTreeAuthorNormal cascade level or such, and change the
-        // cascade order, if we allow to forward parts to even outer trees.
-        //
-        // Though the current thing kinda works because we apply them after
-        // the outer tree, so as long as we don't allow forwarding we're
-        // good.
+        // TODO(emilio): Cascade order will need to increment for each tree when
+        // we implement forwarding.
+        let shadow_cascade_order = ShadowCascadeOrder::for_innermost_containing_tree();
         if let Some(part_rules) = part_rules {
             let containing_host = containing_shadow.map(|s| s.host());
             let element = self.element;
             let rule_hash_target = self.rule_hash_target;
             let rules = &mut self.rules;
             let flags_setter = &mut self.flags_setter;
-            let shadow_cascade_order = self.shadow_cascade_order;
-            let cascade_level = CascadeLevel::SameTreeAuthorNormal;
+            let cascade_level = CascadeLevel::AuthorNormal {
+                shadow_cascade_order,
+            };
             let start = rules.len();
             self.context.with_shadow_host(containing_host, |context| {
                 rule_hash_target.each_part(|p| {
                     if let Some(part_rules) = part_rules.get(p) {
                         SelectorMap::get_matching_rules(
                             element,
                             &part_rules,
                             rules,
                             context,
                             flags_setter,
                             cascade_level,
-                            shadow_cascade_order,
                         );
                     }
                 });
             });
             sort_rules_from(rules, start);
         }
     }
 
     fn collect_style_attribute(&mut self) {
         if let Some(sa) = self.style_attribute {
             self.rules
                 .push(ApplicableDeclarationBlock::from_declarations(
                     sa.clone_arc(),
-                    CascadeLevel::StyleAttributeNormal,
+                    CascadeLevel::same_tree_author_normal(),
                 ));
         }
     }
 
     fn collect_animation_rules(&mut self) {
         if let Some(so) = self.smil_override {
             self.rules
                 .push(ApplicableDeclarationBlock::from_declarations(
@@ -428,17 +428,16 @@ where
             return;
         }
         self.collect_presentational_hints();
         // FIXME(emilio): Should the author styles enabled stuff avoid the
         // presentational hints from getting pushed? See bug 1505770.
         if self.stylist.author_styles_enabled() == AuthorStylesEnabled::No {
             return;
         }
-        self.collect_host_rules();
-        self.collect_slotted_rules();
+        self.collect_host_and_slotted_rules();
         self.collect_normal_rules_from_containing_shadow_tree();
         self.collect_document_author_rules();
+        self.collect_style_attribute();
         self.collect_part_rules();
-        self.collect_style_attribute();
         self.collect_animation_rules();
     }
 }
--- a/servo/components/style/rule_tree/mod.rs
+++ b/servo/components/style/rule_tree/mod.rs
@@ -164,25 +164,70 @@ 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:
+/// A counter to track how many shadow root 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 = u8;
+/// See the static functions for the meaning of different values.
+#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd)]
+pub struct ShadowCascadeOrder(i8);
+
+impl ShadowCascadeOrder {
+    /// A level for the outermost shadow tree (the shadow tree we own, and the
+    /// ones from the slots we're slotted in).
+    #[inline]
+    pub fn for_outermost_shadow_tree() -> Self {
+        Self(-1)
+    }
+
+    /// A level for the element's tree.
+    #[inline]
+    fn for_same_tree() -> Self {
+        Self(0)
+    }
+
+    /// A level for the innermost containing tree (the one closest to the
+    /// element).
+    #[inline]
+    pub fn for_innermost_containing_tree() -> Self {
+        Self(1)
+    }
+
+    /// Decrement the level, moving inwards. We should only move inwards if
+    /// we're traversing slots.
+    #[inline]
+    pub fn dec(&mut self) {
+        debug_assert!(self.0 < 0);
+        self.0 = self.0.saturating_sub(1);
+    }
+
+    /// The level, moving inwards. We should only move inwards if we're
+    /// traversing slots.
+    #[inline]
+    pub fn inc(&mut self) {
+        debug_assert_ne!(self.0, -1);
+        self.0 = self.0.saturating_add(1);
+    }
+}
+
+impl std::ops::Neg for ShadowCascadeOrder {
+    type Output = Self;
+    #[inline]
+    fn neg(self) -> Self {
+        Self(self.0.neg())
+    }
+}
 
 impl RuleTree {
     /// Construct a new rule tree.
     pub fn new() -> Self {
         RuleTree {
             root: StrongRuleNode::new(Box::new(RuleNode::root())),
         }
     }
@@ -210,68 +255,44 @@ 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, ShadowCascadeOrder)>,
+        I: Iterator<Item = (StyleSource, CascadeLevel)>,
     {
         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_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_author = SmallVec::<[(StyleSource, ShadowCascadeOrder); 4]>::new();
 
         let mut important_user = SmallVec::<[StyleSource; 4]>::new();
         let mut important_ua = SmallVec::<[StyleSource; 4]>::new();
         let mut transition = None;
 
-        let mut last_cascade_order = 0;
-        for (source, level, shadow_cascade_order) in iter {
-            debug_assert!(level >= last_level, "Not really ordered");
+        for (source, level) in iter {
             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 {
-                    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())
+                    AuthorNormal { shadow_cascade_order } => {
+                        important_author.push((source.clone(), shadow_cascade_order));
                     },
-                    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());
-                    },
                     _ => {},
                 };
             }
 
             // We don't optimize out empty rules, even though we could.
             //
             // Inspector relies on every rule being inserted in the normal level
             // at least once, in order to return the rules with the correct
@@ -285,41 +306,52 @@ impl RuleTree {
                 // There can be at most one transition, and it will come at
                 // the end of the iterator. Stash it and apply it after
                 // !important rules.
                 debug_assert!(transition.is_none());
                 transition = Some(source);
             } else {
                 current = current.ensure_child(self.root.downgrade(), source, level);
             }
-            last_level = level;
         }
 
         // Early-return in the common case of no !important declarations.
         if !found_important {
             return current;
         }
 
-        //
         // Insert important declarations, in order of increasing importance,
         // followed by any transition rule.
         //
-
-        for source in important_same_tree.drain() {
-            current = current.ensure_child(self.root.downgrade(), source, SameTreeAuthorImportant);
+        // Inner shadow wins over same-tree, which wins over outer-shadow.
+        //
+        // We negate the shadow cascade order to preserve the right PartialOrd
+        // behavior.
+        if !important_author.is_empty() &&
+            important_author.first().unwrap().1 != important_author.last().unwrap().1
+        {
+            // We only need to sort if the important rules come from
+            // different trees, but we need this sort to be stable.
+            //
+            // FIXME(emilio): This could maybe be smarter, probably by chunking
+            // the important rules while inserting, and iterating the outer
+            // chunks in reverse order.
+            //
+            // That is, if we have rules with levels like: -1 -1 -1 0 0 0 1 1 1,
+            // we're really only sorting the chunks, while keeping elements
+            // inside the same chunk already sorted. Seems like we could try to
+            // keep a SmallVec-of-SmallVecs with the chunks and just iterate the
+            // outer in reverse.
+            important_author.sort_by_key(|&(_, order)| -order);
         }
 
-        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, shadow_cascade_order) in important_author.drain() {
+            current = current.ensure_child(self.root.downgrade(), source, AuthorImportant {
+                shadow_cascade_order: -shadow_cascade_order,
+            });
         }
 
         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);
@@ -354,21 +386,18 @@ impl RuleTree {
         self.insert_ordered_rules_from(self.root.clone(), iter)
     }
 
     fn insert_ordered_rules_from<'a, I>(&self, from: StrongRuleNode, iter: I) -> StrongRuleNode
     where
         I: Iterator<Item = (StyleSource, CascadeLevel)>,
     {
         let mut current = from;
-        let mut last_level = current.get().level;
         for (source, level) in iter {
-            debug_assert!(last_level <= level, "Not really ordered");
             current = current.ensure_child(self.root.downgrade(), source, level);
-            last_level = level;
         }
         current
     }
 
     /// This can only be called when no other threads is accessing this tree.
     pub unsafe fn gc(&self) {
         self.root.gc();
     }
@@ -434,17 +463,16 @@ impl RuleTree {
     pub fn update_rule_at_level(
         &self,
         level: CascadeLevel,
         pdb: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
         path: &StrongRuleNode,
         guards: &StylesheetGuards,
         important_rules_changed: &mut bool,
     ) -> Option<StrongRuleNode> {
-        debug_assert!(level.is_unique_per_element());
         // TODO(emilio): Being smarter with lifetimes we could avoid a bit of
         // the refcount churn.
         let mut current = path.clone();
         *important_rules_changed = false;
 
         // First walk up until the first less-or-equally specific rule.
         let mut children = SmallVec::<[_; 10]>::new();
         while current.get().level > level {
@@ -463,45 +491,46 @@ impl RuleTree {
         // This is certainly true for HTML style attribute rules, animations and
         // transitions, but could not be so for SMIL animations, which we'd need
         // to special-case (isn't hard, it's just about removing the `if` and
         // special cases, and replacing them for a `while` loop, avoiding the
         // optimizations).
         if current.get().level == level {
             *important_rules_changed |= level.is_important();
 
-            if let Some(pdb) = pdb {
+            let current_decls = current
+                .get()
+                .source
+                .as_ref()
+                .unwrap()
+                .as_declarations();
+
+            // If the only rule at the level we're replacing is exactly the
+            // same as `pdb`, we're done, and `path` is still valid.
+            if let (Some(ref pdb), Some(ref current_decls)) = (pdb, current_decls) {
                 // If the only rule at the level we're replacing is exactly the
                 // 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 current_decls = current
-                    .get()
-                    .source
-                    .as_ref()
-                    .unwrap()
-                    .as_declarations()
-                    .expect("Replacing non-declarations style?");
-                let is_here_already = ArcBorrow::ptr_eq(&pdb, &current_decls);
+                let is_here_already = ArcBorrow::ptr_eq(pdb, current_decls);
                 if is_here_already {
                     debug!("Picking the fast path in rule replacement");
                     return None;
                 }
             }
-            current = current.parent().unwrap().clone();
+
+            if current_decls.is_some() {
+                current = current.parent().unwrap().clone();
+            }
         }
-        debug_assert!(
-            current.get().level != level,
-            "Multiple rules should've been replaced?"
-        );
 
         // Insert the rule if it's relevant at this level in the cascade.
         //
         // These optimizations are likely to be important, because the levels
         // where replacements apply (style and animations) tend to trigger
         // pretty bad styling cases already.
         if let Some(pdb) = pdb {
             if level.is_important() {
@@ -606,105 +635,98 @@ const RULE_TREE_GC_INTERVAL: usize = 300
 ///
 /// 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, Hash, PartialEq, PartialOrd)]
-#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
+#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd)]
 pub enum CascadeLevel {
     /// Normal User-Agent rules.
-    UANormal = 0,
+    UANormal,
     /// User normal rules.
     UserNormal,
     /// Presentational hints.
     PresHints,
-    /// 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,
+    /// Shadow DOM styles from author styles.
+    AuthorNormal {
+        /// The order in the shadow tree hierarchy. This number is relative to
+        /// the tree of the element, and thus the only invariants that need to
+        /// be preserved is:
+        ///
+        ///  * Zero is the same tree as the element that matched the rule. This
+        ///    is important so that we can optimize style attribute insertions.
+        ///
+        ///  * The levels are ordered in accordance with
+        ///    https://drafts.csswg.org/css-scoping/#shadow-cascading
+        shadow_cascade_order: ShadowCascadeOrder,
+    },
     /// SVG SMIL animations.
     SMILOverride,
     /// CSS animations and script-generated animations.
     Animations,
-    /// Author-supplied important rules from the same tree the element came
-    /// from.
-    SameTreeAuthorImportant,
-    /// Style attribute important rules.
-    StyleAttributeImportant,
-    /// Shadow DOM important rules.
-    InnerShadowImportant,
+    /// Author-supplied important rules.
+    AuthorImportant {
+        /// The order in the shadow tree hierarchy, inverted, so that PartialOrd
+        /// does the right thing.
+        shadow_cascade_order: ShadowCascadeOrder,
+    },
     /// User important rules.
     UserImportant,
     /// User-agent important rules.
     UAImportant,
     /// Transitions
     ///
     /// NB: If this changes from being last, change from_byte below.
     Transitions,
 }
 
 impl CascadeLevel {
-    /// Converts a raw byte to a CascadeLevel.
-    pub unsafe fn from_byte(byte: u8) -> Self {
-        debug_assert!(byte <= CascadeLevel::Transitions as u8);
-        mem::transmute(byte)
-    }
-
     /// Select a lock guard for this level
     pub fn guard<'a>(&self, guards: &'a StylesheetGuards<'a>) -> &'a SharedRwLockReadGuard<'a> {
         match *self {
             CascadeLevel::UANormal |
             CascadeLevel::UserNormal |
             CascadeLevel::UserImportant |
             CascadeLevel::UAImportant => guards.ua_or_user,
             _ => guards.author,
         }
     }
 
-    /// Returns whether this cascade level is unique per element, in which case
-    /// we can replace the path in the cascade without fear.
-    pub fn is_unique_per_element(&self) -> bool {
-        match *self {
-            CascadeLevel::Transitions |
-            CascadeLevel::Animations |
-            CascadeLevel::SMILOverride |
-            CascadeLevel::StyleAttributeNormal |
-            CascadeLevel::StyleAttributeImportant => true,
-            _ => false,
+    /// Returns the cascade level for author important declarations from the
+    /// same tree as the element.
+    #[inline]
+    pub fn same_tree_author_important() -> Self {
+        CascadeLevel::AuthorImportant {
+            shadow_cascade_order: ShadowCascadeOrder::for_same_tree(),
+        }
+    }
+
+    /// Returns the cascade level for author normal declarations from the same
+    /// tree as the element.
+    #[inline]
+    pub fn same_tree_author_normal() -> Self {
+        CascadeLevel::AuthorNormal {
+            shadow_cascade_order: ShadowCascadeOrder::for_same_tree(),
         }
     }
 
     /// Returns whether this cascade level represents important rules of some
     /// sort.
     #[inline]
     pub fn is_important(&self) -> bool {
         match *self {
-            CascadeLevel::SameTreeAuthorImportant |
-            CascadeLevel::InnerShadowImportant |
-            CascadeLevel::StyleAttributeImportant |
+            CascadeLevel::AuthorImportant { .. } |
             CascadeLevel::UserImportant |
             CascadeLevel::UAImportant => true,
             _ => false,
         }
     }
 
     /// Returns the importance relevant for this rule. Pretty similar to
     /// `is_important`.
@@ -719,24 +741,20 @@ impl CascadeLevel {
 
     /// Returns the cascade origin of the rule.
     #[inline]
     pub fn origin(&self) -> Origin {
         match *self {
             CascadeLevel::UAImportant | CascadeLevel::UANormal => Origin::UserAgent,
             CascadeLevel::UserImportant | CascadeLevel::UserNormal => Origin::User,
             CascadeLevel::PresHints |
-            CascadeLevel::InnerShadowNormal |
-            CascadeLevel::SameTreeAuthorNormal |
-            CascadeLevel::StyleAttributeNormal |
+            CascadeLevel::AuthorNormal { .. } |
+            CascadeLevel::AuthorImportant { .. } |
             CascadeLevel::SMILOverride |
             CascadeLevel::Animations |
-            CascadeLevel::SameTreeAuthorImportant |
-            CascadeLevel::StyleAttributeImportant |
-            CascadeLevel::InnerShadowImportant |
             CascadeLevel::Transitions => Origin::Author,
         }
     }
 
     /// Returns whether this cascade level represents an animation rules.
     #[inline]
     pub fn is_animation(&self) -> bool {
         match *self {
@@ -1141,16 +1159,25 @@ impl StrongRuleNode {
     fn ensure_child(
         &self,
         root: WeakRuleNode,
         source: StyleSource,
         level: CascadeLevel,
     ) -> StrongRuleNode {
         use parking_lot::RwLockUpgradableReadGuard;
 
+        debug_assert!(
+            self.get().level <= level,
+            "Should be ordered (instead {:?} > {:?}), from {:?} and {:?}",
+            self.get().level,
+            level,
+            self.get().source,
+            source,
+        );
+
         let key = ChildKey(level, source.key());
 
         let read_guard = self.get().children.upgradable_read();
         if let Some(child) = read_guard.get(&key) {
             return child.upgrade();
         }
 
         RwLockUpgradableReadGuard::upgrade(read_guard).get_or_insert_with(key, move || {
@@ -1443,65 +1470,50 @@ impl StrongRuleNode {
                         return None;
                     }
                     match declaration.id() {
                         PropertyDeclarationId::Longhand(id) => Some((id, declaration)),
                         _ => None,
                     }
                 });
 
-                match node.cascade_level() {
-                    // Non-author rules:
-                    CascadeLevel::UANormal |
-                    CascadeLevel::UAImportant |
-                    CascadeLevel::UserNormal |
-                    CascadeLevel::UserImportant => {
-                        for (id, declaration) in longhands {
-                            if properties.contains(id) {
-                                // This property was set by a non-author rule.
-                                // Stop looking for it in this element's rule
-                                // nodes.
-                                properties.remove(id);
+                let is_author = node.cascade_level().origin() == Origin::Author;
+                for (id, declaration) in longhands {
+                    if !properties.contains(id) {
+                        continue;
+                    }
 
-                                // However, if it is inherited, then it might be
-                                // inherited from an author rule from an
-                                // ancestor element's rule nodes.
-                                if declaration.get_css_wide_keyword() ==
-                                    Some(CSSWideKeyword::Inherit)
-                                {
-                                    have_explicit_ua_inherit = true;
-                                    inherited_properties.insert(id);
-                                }
+                    if is_author {
+                        if !author_colors_allowed {
+                            // FIXME(emilio): this looks wrong, this should
+                            // do: if color is not transparent, then return
+                            // true, or something.
+                            if let PropertyDeclaration::BackgroundColor(ref color) =
+                                *declaration
+                            {
+                                return *color == Color::transparent();
                             }
                         }
-                    },
-                    // Author rules:
-                    CascadeLevel::PresHints |
-                    CascadeLevel::SameTreeAuthorNormal |
-                    CascadeLevel::InnerShadowNormal |
-                    CascadeLevel::StyleAttributeNormal |
-                    CascadeLevel::SMILOverride |
-                    CascadeLevel::Animations |
-                    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
-                                    {
-                                        return *color == Color::transparent();
-                                    }
-                                }
-                                return true;
-                            }
-                        }
-                    },
+                        return true;
+                    }
+
+                    // This property was set by a non-author rule.
+                    // Stop looking for it in this element's rule
+                    // nodes.
+                    properties.remove(id);
+
+                    // However, if it is inherited, then it might be
+                    // inherited from an author rule from an
+                    // ancestor element's rule nodes.
+                    if declaration.get_css_wide_keyword() ==
+                        Some(CSSWideKeyword::Inherit)
+                    {
+                        have_explicit_ua_inherit = true;
+                        inherited_properties.insert(id);
+                    }
                 }
             }
 
             if !have_explicit_ua_inherit {
                 break;
             }
 
             // Continue to the parent element and search for the inherited properties.
--- a/servo/components/style/selector_map.rs
+++ b/servo/components/style/selector_map.rs
@@ -5,17 +5,17 @@
 //! A data structure to efficiently index structs containing selectors by local
 //! name, ids and hash.
 
 use crate::applicable_declarations::ApplicableDeclarationList;
 use crate::context::QuirksMode;
 use crate::dom::TElement;
 use crate::hash::map as hash_map;
 use crate::hash::{HashMap, HashSet};
-use crate::rule_tree::{CascadeLevel, ShadowCascadeOrder};
+use crate::rule_tree::CascadeLevel;
 use crate::selector_parser::SelectorImpl;
 use crate::stylist::Rule;
 use crate::{Atom, LocalName, Namespace, WeakAtom};
 use fallible::FallibleVec;
 use hashglobe::FailedAllocationError;
 use precomputed_hash::PrecomputedHash;
 use selectors::matching::{matches_selector, ElementSelectorFlags, MatchingContext};
 use selectors::parser::{Combinator, Component, SelectorIter};
@@ -166,17 +166,16 @@ 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;
         }
 
@@ -185,107 +184,100 @@ impl SelectorMap<Rule> {
         if rule_hash_target.is_root() {
             SelectorMap::get_matching_rules(
                 element,
                 &self.root,
                 matching_rules_list,
                 context,
                 flags_setter,
                 cascade_level,
-                shadow_cascade_order,
             );
         }
 
         if let Some(id) = rule_hash_target.id() {
             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,
             )
         }
 
         if let Some(rules) = self.namespace_hash.get(rule_hash_target.namespace()) {
             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,
         );
     }
 
     /// Adds rules in `rules` that match `element` to the `matching_rules` list.
     pub(crate) 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, shadow_cascade_order),
+                    rule.to_applicable_declaration_block(cascade_level),
                 );
             }
         }
     }
 }
 
 impl<T: SelectorMapEntry> SelectorMap<T> {
     /// Inserts into the correct hash, trying id, class, localname and
--- a/servo/components/style/servo/selector_parser.rs
+++ b/servo/components/style/servo/selector_parser.rs
@@ -168,16 +168,22 @@ impl PseudoElement {
     }
 
     /// Whether the current pseudo element is :first-line
     #[inline]
     pub fn is_first_line(&self) -> bool {
         false
     }
 
+    /// Whether this pseudo-element is the ::-moz-color-swatch pseudo.
+    #[inline]
+    pub fn is_color_swatch(&self) -> bool {
+        false
+    }
+
     /// Whether this pseudo-element is eagerly-cascaded.
     #[inline]
     pub fn is_eager(&self) -> bool {
         self.cascade_type() == PseudoElementCascadeType::Eager
     }
 
     /// Whether this pseudo-element is lazily-cascaded.
     #[inline]
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -13,17 +13,17 @@ use crate::font_metrics::FontMetricsProv
 use crate::gecko_bindings::structs::{ServoStyleSetSizes, StyleRuleInclusion};
 use crate::invalidation::element::invalidation_map::InvalidationMap;
 use crate::invalidation::media_queries::{EffectiveMediaQueryResults, ToMediaListKey};
 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::{containing_shadow_ignoring_svg_use, RuleCollector};
-use crate::rule_tree::{CascadeLevel, RuleTree, ShadowCascadeOrder, StrongRuleNode, StyleSource};
+use crate::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
 use crate::selector_map::{PrecomputedHashMap, PrecomputedHashSet, SelectorMap, SelectorMapEntry};
 use crate::selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap};
 use crate::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
 use crate::stylesheet_set::{DataValidity, DocumentStylesheetSet, SheetRebuildKind};
 use crate::stylesheet_set::{DocumentStylesheetFlusher, SheetCollectionFlusher};
 use crate::stylesheets::keyframes_rule::KeyframesAnimation;
 use crate::stylesheets::viewport_rule::{self, MaybeNew, ViewportRule};
 use crate::stylesheets::StyleRule;
@@ -1319,17 +1319,17 @@ impl Stylist {
         use crate::font_metrics::get_metrics_provider_for_product;
 
         let block = declarations.read_with(guards.author);
         let iter_declarations = || {
             block
                 .declaration_importance_iter()
                 .map(|(declaration, importance)| {
                     debug_assert!(!importance.important());
-                    (declaration, CascadeLevel::StyleAttributeNormal)
+                    (declaration, CascadeLevel::same_tree_author_normal())
                 })
         };
 
         let metrics = get_metrics_provider_for_product();
 
         // We don't bother inserting these declarations in the rule tree, since
         // it'd be quite useless and slow.
         properties::apply_declarations::<E, _, _>(
@@ -1982,17 +1982,16 @@ impl CascadeData {
                                     .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(),
-                                        0,
                                     ));
                                 continue;
                             }
                             if pseudo.is_unknown_webkit_pseudo_element() {
                                 continue;
                             }
                         }
 
@@ -2318,25 +2317,23 @@ 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::from_rule(self.style_rule.clone());
         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>>,
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -3530,17 +3530,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::SameTreeAuthorNormal,
+                    Origin::Author => CascadeLevel::same_tree_author_normal(),
                 };
                 for rule in data.pages.iter() {
                     declarations.push(ApplicableDeclarationBlock::from_declarations(
                         rule.read_with(level.guard(&guards)).block.clone(),
                         level,
                     ));
                 }
             }
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-shadow-parts/simple-important-important.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[simple-important-important.html]
-  [Part in selected host is styled]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-shadow-parts/simple-inline.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[simple-inline.html]
-  [Part in selected host is styled]
-    expected: FAIL
-