style: Make :host() and ::slotted() account for the inner selector's specificity.

As resolved in https://github.com/w3c/csswg-drafts/issues/1915.

Bug: 1454165
Reviewed-by: xidorn
Differential Revision: https://phabricator.services.mozilla.com/D1849
This commit is contained in:
Emilio Cobos Álvarez 2018-06-28 10:58:06 +00:00
parent 8688c53f07
commit e6d62b685b
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C

View file

@ -23,7 +23,7 @@ use sink::Push;
use smallvec::{self, SmallVec}; use smallvec::{self, SmallVec};
use std::cmp; use std::cmp;
use std::iter; use std::iter;
use std::ops::Add; use std::ops::{AddAssign, Add};
use std::ptr; use std::ptr;
use std::slice; use std::slice;
@ -228,6 +228,16 @@ struct Specificity {
element_selectors: u32, element_selectors: u32,
} }
impl AddAssign for Specificity {
#[inline]
fn add_assign(&mut self, rhs: Self) {
self.id_selectors += rhs.id_selectors;
self.class_like_selectors += rhs.class_like_selectors;
self.element_selectors += rhs.element_selectors;
}
}
impl Add for Specificity { impl Add for Specificity {
type Output = Specificity; type Output = Specificity;
@ -251,6 +261,7 @@ impl Default for Specificity {
} }
impl From<u32> for Specificity { impl From<u32> for Specificity {
#[inline]
fn from(value: u32) -> Specificity { fn from(value: u32) -> Specificity {
assert!(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT); assert!(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT);
Specificity { Specificity {
@ -262,6 +273,7 @@ impl From<u32> for Specificity {
} }
impl From<Specificity> for u32 { impl From<Specificity> for u32 {
#[inline]
fn from(specificity: Specificity) -> u32 { fn from(specificity: Specificity) -> u32 {
cmp::min(specificity.id_selectors, MAX_10BIT) << 20 | cmp::min(specificity.id_selectors, MAX_10BIT) << 20 |
cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10 | cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10 |
@ -298,17 +310,29 @@ where
builder, builder,
); );
} }
// FIXME(emilio): Spec doesn't define any particular specificity for Component::PseudoElement(..) | Component::LocalName(..) => {
// ::slotted(), so apply the general rule for pseudos per:
//
// https://github.com/w3c/csswg-drafts/issues/1915
//
// Though other engines compute it dynamically, so maybe we should
// do that instead, eventually.
Component::Slotted(..) | Component::PseudoElement(..) | Component::LocalName(..) => {
specificity.element_selectors += 1 specificity.element_selectors += 1
}, },
Component::ID(..) => specificity.id_selectors += 1, Component::Slotted(ref selector) => {
specificity.element_selectors += 1;
// Note that due to the way ::slotted works we only compete with
// other ::slotted rules, so the above rule doesn't really
// matter, but we do it still for consistency with other
// pseudo-elements.
//
// See: https://github.com/w3c/csswg-drafts/issues/1915
*specificity += Specificity::from(selector.specificity());
},
Component::Host(ref selector) => {
specificity.class_like_selectors += 1;
if let Some(ref selector) = *selector {
// See: https://github.com/w3c/csswg-drafts/issues/1915
*specificity += Specificity::from(selector.specificity());
}
}
Component::ID(..) => {
specificity.id_selectors += 1;
},
Component::Class(..) | Component::Class(..) |
Component::AttributeInNoNamespace { .. } | Component::AttributeInNoNamespace { .. } |
Component::AttributeInNoNamespaceExists { .. } | Component::AttributeInNoNamespaceExists { .. } |
@ -319,7 +343,6 @@ where
Component::Root | Component::Root |
Component::Empty | Component::Empty |
Component::Scope | Component::Scope |
Component::Host(..) |
Component::NthChild(..) | Component::NthChild(..) |
Component::NthLastChild(..) | Component::NthLastChild(..) |
Component::NthOfType(..) | Component::NthOfType(..) |
@ -327,7 +350,9 @@ where
Component::FirstOfType | Component::FirstOfType |
Component::LastOfType | Component::LastOfType |
Component::OnlyOfType | Component::OnlyOfType |
Component::NonTSPseudoClass(..) => specificity.class_like_selectors += 1, Component::NonTSPseudoClass(..) => {
specificity.class_like_selectors += 1;
},
Component::ExplicitUniversalType | Component::ExplicitUniversalType |
Component::ExplicitAnyNamespace | Component::ExplicitAnyNamespace |
Component::ExplicitNoNamespace | Component::ExplicitNoNamespace |