use crate::properties::PropertyDeclarationBlock;
use crate::rule_tree::{CascadeLevel, StyleSource};
use crate::shared_lock::Locked;
use crate::stylesheets::layer_rule::LayerOrder;
use servo_arc::Arc;
use smallvec::SmallVec;
pub type ApplicableDeclarationList = SmallVec<[ApplicableDeclarationBlock; 16]>;
const SOURCE_ORDER_BITS: usize = 24;
const SOURCE_ORDER_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1;
const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX;
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
pub struct CascadePriority {
cascade_level: CascadeLevel,
layer_order: LayerOrder,
}
const_assert_eq!(
std::mem::size_of::<CascadePriority>(),
std::mem::size_of::<u32>()
);
impl PartialOrd for CascadePriority {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for CascadePriority {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.cascade_level.cmp(&other.cascade_level).then_with(|| {
let ordering = self.layer_order.cmp(&other.layer_order);
if ordering == std::cmp::Ordering::Equal {
return ordering;
}
if self.cascade_level.is_important()
&& !self.layer_order.is_style_attribute_layer()
&& !other.layer_order.is_style_attribute_layer()
{
ordering.reverse()
} else {
ordering
}
})
}
}
impl CascadePriority {
pub fn new(cascade_level: CascadeLevel, layer_order: LayerOrder) -> Self {
Self {
cascade_level,
layer_order,
}
}
#[inline]
pub fn layer_order(&self) -> LayerOrder {
self.layer_order
}
#[inline]
pub fn cascade_level(&self) -> CascadeLevel {
self.cascade_level
}
pub fn allows_when_reverted(&self, other: &Self, origin_revert: bool) -> bool {
if origin_revert {
other.cascade_level.origin() < self.cascade_level.origin()
} else {
other.unimportant() < self.unimportant()
}
}
pub fn unimportant(&self) -> Self {
Self::new(self.cascade_level().unimportant(), self.layer_order())
}
pub fn important(&self) -> Self {
Self::new(self.cascade_level().important(), self.layer_order())
}
pub fn same_tree_author_normal_at_root_layer() -> Self {
Self::new(CascadeLevel::same_tree_author_normal(), LayerOrder::root())
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
pub struct ScopeProximity(u16);
impl PartialOrd for ScopeProximity {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ScopeProximity {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
other.0.cmp(&self.0)
}
}
const PROXIMITY_INFINITY: u16 = u16::MAX;
impl ScopeProximity {
pub fn new(proximity: usize) -> Self {
if cfg!(debug_assertions) && proximity >= PROXIMITY_INFINITY as usize {
warn!("Proximity out of bounds");
}
Self(proximity.clamp(0, (PROXIMITY_INFINITY - 1) as usize) as u16)
}
pub fn infinity() -> Self {
Self(PROXIMITY_INFINITY)
}
pub fn get(&self) -> Option<u16> {
(self.0 != PROXIMITY_INFINITY).then(|| self.0)
}
}
#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
pub struct ApplicableDeclarationBlock {
#[ignore_malloc_size_of = "Arc"]
pub source: StyleSource,
source_order: u32,
pub specificity: u32,
pub scope_proximity: ScopeProximity,
pub cascade_priority: CascadePriority,
}
impl ApplicableDeclarationBlock {
#[inline]
pub fn from_declarations(
declarations: Arc<Locked<PropertyDeclarationBlock>>,
level: CascadeLevel,
layer_order: LayerOrder,
) -> Self {
ApplicableDeclarationBlock {
source: StyleSource::from_declarations(declarations),
source_order: 0,
specificity: 0,
scope_proximity: ScopeProximity::infinity(),
cascade_priority: CascadePriority::new(level, layer_order),
}
}
#[inline]
pub fn new(
source: StyleSource,
source_order: u32,
level: CascadeLevel,
specificity: u32,
layer_order: LayerOrder,
scope_proximity: ScopeProximity,
) -> Self {
ApplicableDeclarationBlock {
source,
source_order: source_order & SOURCE_ORDER_MASK,
specificity,
scope_proximity,
cascade_priority: CascadePriority::new(level, layer_order),
}
}
#[inline]
pub fn source_order(&self) -> u32 {
self.source_order
}
#[inline]
pub fn level(&self) -> CascadeLevel {
self.cascade_priority.cascade_level()
}
#[inline]
pub fn layer_order(&self) -> LayerOrder {
self.cascade_priority.layer_order()
}
#[inline]
pub fn scope_proximity(&self) -> ScopeProximity {
self.scope_proximity
}
#[inline]
pub fn for_rule_tree(self) -> (StyleSource, CascadePriority) {
(self.source, self.cascade_priority)
}
#[inline]
pub fn sort_key(&self) -> (LayerOrder, u32, ScopeProximity, u32) {
(
self.layer_order(),
self.specificity,
self.scope_proximity(),
self.source_order(),
)
}
}
size_of_test!(ApplicableDeclarationBlock, 24);